aiobungie

A Pythonic async/await wrapper for interacting with the Bungie API.

Base client.

Example
import aiobungie

client = aiobungie.Client('YOUR_API_KEY')

# Search for Destiny2 users.
async def main() -> None:
    users = await client.search_users('Crit')

    # Iterate over the users and take the first 5 results.
    for user in users.take(5):
        print(f'{user.name} ({user.code})')

        # Iterate through the users memberships.
        for membership in user.memberships:
            print(membership.type, membership.id)

client.run(main()) # or asyncio.run(main())

Single RESTClient instance.

The difference between base client and the REST clients:

  • No Hight-Level concepts.
  • All returned data are pure JSON objects from the API.
  • No object creation.
Example
import aiobungie

async def main() -> None:
    # Using `async with` context manager to close the session properly.
    async with aiobungie.RESTClient("TOKEN") as rest:
        payload = await rest.fetch_player('Fate怒', 4275)

        for membership in payload:
            print(membership['membershipId'], membership['iconPath'])

import asyncio
asyncio.run(main())

REST client pool.

A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.

Example
import aiobungie
import asyncio

pool = aiobungie.RESTPool("token")

async def func1() -> None:
    async with pool.acquire() as instance:
        tokens = await instance.fetch_oauth2_tokens('code')
        pool.metadata['tokens'] = tokens

# Other instance may access the tokens from pool since its shared.

async def func2() -> None:
    async with pool.acquire() as instance:
        tokens = pool.metadata['tokens']
        tokens = await instance.refresh_access_token(tokens.refresh_token)

async def main() -> None:
    await asyncio.gather(func1(), func2())

asyncio.run(main())

Should you use the base client or the REST client? This returns to you. For an example if you're building a website.

You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.

Or of you're building a Discord bot for an example or something simple. The base client is the way to go.

  1# MIT License
  2#
  3# Copyright (c) 2020 - Present nxtlo
  4#
  5# Permission is hereby granted, free of charge, to any person obtaining a copy
  6# of this software and associated documentation files (the "Software"), to deal
  7# in the Software without restriction, including without limitation the rights
  8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9# copies of the Software, and to permit persons to whom the Software is
 10# furnished to do so, subject to the following conditions:
 11#
 12# The above copyright notice and this permission notice shall be included in all
 13# copies or substantial portions of the Software.
 14#
 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21# SOFTWARE.
 22
 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API.
 24
 25Base client.
 26
 27Example
 28-------
 29```py
 30import aiobungie
 31
 32client = aiobungie.Client('YOUR_API_KEY')
 33
 34# Search for Destiny2 users.
 35async def main() -> None:
 36    users = await client.search_users('Crit')
 37
 38    # Iterate over the users and take the first 5 results.
 39    for user in users.take(5):
 40        print(f'{user.name} ({user.code})')
 41
 42        # Iterate through the users memberships.
 43        for membership in user.memberships:
 44            print(membership.type, membership.id)
 45
 46client.run(main()) # or asyncio.run(main())
 47```
 48
 49Single RESTClient instance.
 50
 51The difference between base client and the REST clients:
 52
 53* No Hight-Level concepts.
 54* All returned data are pure JSON objects from the API.
 55* No object creation.
 56
 57Example
 58-------
 59```py
 60import aiobungie
 61
 62async def main() -> None:
 63    # Using `async with` context manager to close the session properly.
 64    async with aiobungie.RESTClient("TOKEN") as rest:
 65        payload = await rest.fetch_player('Fate怒', 4275)
 66
 67        for membership in payload:
 68            print(membership['membershipId'], membership['iconPath'])
 69
 70import asyncio
 71asyncio.run(main())
 72```
 73
 74REST client pool.
 75
 76A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection.
 77
 78Example
 79-------
 80```py
 81import aiobungie
 82import asyncio
 83
 84pool = aiobungie.RESTPool("token")
 85
 86async def func1() -> None:
 87    async with pool.acquire() as instance:
 88        tokens = await instance.fetch_oauth2_tokens('code')
 89        pool.metadata['tokens'] = tokens
 90
 91# Other instance may access the tokens from pool since its shared.
 92
 93async def func2() -> None:
 94    async with pool.acquire() as instance:
 95        tokens = pool.metadata['tokens']
 96        tokens = await instance.refresh_access_token(tokens.refresh_token)
 97
 98async def main() -> None:
 99    await asyncio.gather(func1(), func2())
100
101asyncio.run(main())
102```
103
104Should you use the base client or the REST client?
105This returns to you. For an example if you're building a website.
106
107You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects.
108Which gives you the freedom to deserialize it and implement your own logic in the front-end.
109
110Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
111"""
112
113
114from __future__ import annotations
115
116from aiobungie import builders
117from aiobungie import crates
118from aiobungie import interfaces
119from aiobungie import traits
120from aiobungie import typedefs
121from aiobungie import url
122from aiobungie.client import Client
123from aiobungie.error import *
124from aiobungie.internal import iterators
125from aiobungie.internal.assets import Image
126from aiobungie.internal.enums import *
127from aiobungie.internal.factory import Factory
128from aiobungie.internal.iterators import *
129from aiobungie.rest import *
130from aiobungie.undefined import Undefined
131from aiobungie.undefined import UndefinedOr
132from aiobungie.undefined import UndefinedType
133
134from ._info import __about__
135from ._info import __author__
136from ._info import __docs__
137from ._info import __email__
138from ._info import __license__
139from ._info import __url__
140from ._info import __version__
141
142# Alias for crate for backwards compatibility.
143crate = crates
144
145# Activity enums
146from .crates.activity import Difficulty
147
148# Components enums
149from .crates.components import ComponentFields
150from .crates.components import ComponentPrivacy
151
152# Entity enums
153from .crates.entity import GatingScope
154from .crates.entity import ObjectiveUIStyle
155from .crates.entity import ValueUIStyle
156
157# Fireteam enums.
158from .crates.fireteams import FireteamActivity
159from .crates.fireteams import FireteamDate
160from .crates.fireteams import FireteamLanguage
161from .crates.fireteams import FireteamPlatform
162
163# Records enums
164from .crates.records import RecordState
165
166__all__ = [mod for mod in dir() if not mod.startswith("_")]  # type: ignore
@attrs.define(auto_exc=True)
class AiobungieError(builtins.RuntimeError):
57@attrs.define(auto_exc=True)
58class AiobungieError(RuntimeError):
59    """Base exception class that all other errors inherit from."""

Base exception class that all other errors inherit from.

AiobungieError()
2def __init__(self, ):
3    BaseException.__init__(self, )

Method generated by attrs for class AiobungieError.

Inherited Members
builtins.BaseException
with_traceback
args
@typing.final
class AmmoType(builtins.int, aiobungie.Enum):
646@typing.final
647class AmmoType(int, Enum):
648    """AN enum for Detyiny 2 ammo types."""
649
650    NONE = 0
651    PRIMARY = 1
652    SPECIAL = 2
653    HEAVY = 3

AN enum for Detyiny 2 ammo types.

NONE = <AmmoType.NONE: 0>
PRIMARY = <AmmoType.PRIMARY: 1>
SPECIAL = <AmmoType.SPECIAL: 2>
HEAVY = <AmmoType.HEAVY: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class BadRequest(aiobungie.HTTPError):
147@attrs.define(auto_exc=True)
148class BadRequest(HTTPError):
149    """Bad requests exceptions."""
150
151    url: typing.Optional[typedefs.StrOrURL]
152    """The URL/endpoint caused this error."""
153
154    body: typing.Any
155    """The response body."""
156
157    headers: multidict.CIMultiDictProxy[str]
158    """The response headers."""
159
160    http_status: http.HTTPStatus = attrs.field(default=http.HTTPStatus.BAD_REQUEST)

Bad requests exceptions.

BadRequest( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], http_status: http.HTTPStatus = <HTTPStatus.BAD_REQUEST: 400>)
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default):
3    self.message = message
4    self.url = url
5    self.body = body
6    self.headers = headers
7    self.http_status = http_status
8    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status)

Method generated by attrs for class BadRequest.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

http_status: http.HTTPStatus

The response status.

Inherited Members
HTTPError
message
builtins.BaseException
with_traceback
args
@typing.final
class ClanMemberType(builtins.int, aiobungie.Enum):
701@typing.final
702class ClanMemberType(int, Enum):
703    """An enum for bungie clan member types."""
704
705    NONE = 0
706    BEGINNER = 1
707    MEMBER = 2
708    ADMIN = 3
709    ACTING_FOUNDER = 4
710    FOUNDER = 5

An enum for bungie clan member types.

NONE = <ClanMemberType.NONE: 0>
BEGINNER = <ClanMemberType.BEGINNER: 1>
MEMBER = <ClanMemberType.MEMBER: 2>
ADMIN = <ClanMemberType.ADMIN: 3>
ACTING_FOUNDER = <ClanMemberType.ACTING_FOUNDER: 4>
FOUNDER = <ClanMemberType.FOUNDER: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Class(builtins.int, aiobungie.Enum):
477@typing.final
478class Class(int, Enum):
479    """An Enum for Destiny character classes."""
480
481    TITAN = 0
482    HUNTER = 1
483    WARLOCK = 2
484    UNKNOWN = 3

An Enum for Destiny character classes.

TITAN = <Class.TITAN: 0>
HUNTER = <Class.HUNTER: 1>
WARLOCK = <Class.WARLOCK: 2>
UNKNOWN = <Class.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Client(aiobungie.traits.ClientApp):
  61class Client(traits.ClientApp):
  62    """Standard Bungie API client application.
  63
  64    This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory`
  65    and returns `aiobungie.crates` Python object implementations of the responses.
  66
  67    A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts.
  68
  69    Example
  70    -------
  71    ```py
  72    import aiobungie
  73
  74    client = aiobungie.Client('...')
  75
  76    async def main():
  77        async with client.rest:
  78            user = await client.fetch_current_user_memberships('...')
  79            print(user)
  80    ```
  81
  82    Parameters
  83    -----------
  84    token: `str`
  85        Your Bungie's API key or Token from the developer's portal.
  86
  87    Other Parameters
  88    ----------------
  89    rest_client: `aiobungie.interfaces.RESTInterface | None`
  90        An optional rest client instance you can pass.
  91        If set to `None` then the client will use the default instance.
  92
  93    max_retries : `int`
  94        The max retries number to retry if the request hit a `5xx` status code.
  95    max_ratelimit_retries : `int`
  96        The max retries number to retry if the request hit a `429` status code. Defaults to `3`.
  97    client_secret : `str | None`
  98        An optional application client secret,
  99        This is only needed if you're fetching OAuth2 tokens with this client.
 100    client_id : `int | None`
 101        An optional application client id,
 102        This is only needed if you're fetching OAuth2 tokens with this client.
 103    """
 104
 105    __slots__ = ("_rest", "_factory", "_client_secret", "_client_id")
 106
 107    def __init__(
 108        self,
 109        token: str,
 110        /,
 111        client_secret: typing.Optional[str] = None,
 112        client_id: typing.Optional[int] = None,
 113        *,
 114        rest_client: typing.Optional[interfaces.RESTInterface] = None,
 115        max_retries: int = 4,
 116        max_ratelimit_retries: int = 3,
 117    ) -> None:
 118
 119        self._client_secret = client_secret
 120        self._client_id = client_id
 121
 122        self._rest = (
 123            rest_client
 124            if rest_client is not None
 125            else rest_.RESTClient(
 126                token,
 127                client_secret,
 128                client_id,
 129                max_retries=max_retries,
 130                max_ratelimit_retries=max_ratelimit_retries,
 131            )
 132        )
 133
 134        self._factory = factory_.Factory(self)
 135
 136    @property
 137    def factory(self) -> factory_.Factory:
 138        return self._factory
 139
 140    @property
 141    def rest(self) -> interfaces.RESTInterface:
 142        return self._rest
 143
 144    @property
 145    def request(self) -> Client:
 146        return copy.copy(self)
 147
 148    @property
 149    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 150        return self._rest.metadata
 151
 152    def run(
 153        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
 154    ) -> None:
 155        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
 156        try:
 157            if not loop.is_running():
 158                loop.set_debug(debug)
 159                loop.run_until_complete(future)
 160
 161        except Exception as exc:
 162            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
 163
 164        except KeyboardInterrupt:
 165            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
 166            return
 167
 168    # * User methods.
 169
 170    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
 171        """Fetch and return a user object of the bungie net user associated with account.
 172
 173        .. warning::
 174            This method requires OAuth2 scope and a Bearer access token.
 175
 176        Parameters
 177        ----------
 178        access_token : `str`
 179            A valid Bearer access token for the authorization.
 180
 181        Returns
 182        -------
 183        `aiobungie.crates.user.User`
 184            A user object includes the Destiny memberships and Bungie.net user.
 185        """
 186        resp = await self.rest.fetch_current_user_memberships(access_token)
 187
 188        return self.factory.deserialize_user(resp)
 189
 190    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
 191        """Fetch a Bungie user by their BungieNet id.
 192
 193        .. note::
 194            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
 195            for other memberships.
 196
 197        Parameters
 198        ----------
 199        id: `int`
 200            The user id.
 201
 202        Returns
 203        -------
 204        `aiobungie.crates.user.BungieUser`
 205            A Bungie user.
 206
 207        Raises
 208        ------
 209        `aiobungie.error.NotFound`
 210            The user was not found.
 211        """
 212        payload = await self.rest.fetch_bungie_user(id)
 213
 214        return self.factory.deserialize_bungie_user(payload)
 215
 216    async def search_users(
 217        self, name: str, /
 218    ) -> iterators.FlatIterator[user.SearchableDestinyUser]:
 219        """Search for players and return all players that matches the same name.
 220
 221        Parameters
 222        ----------
 223        name : `buildins.str`
 224            The user name.
 225
 226        Returns
 227        -------
 228        `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]`
 229            A sequence of destiny memberships.
 230        """
 231        payload = await self.rest.search_users(name)
 232
 233        return iterators.FlatIterator(
 234            [
 235                self.factory.deserialize_searched_user(user)
 236                for user in payload["searchResults"]
 237            ]
 238        )
 239
 240    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
 241        """Fetch all available user themes.
 242
 243        Returns
 244        -------
 245        `collections.Sequence[aiobungie.crates.user.UserThemes]`
 246            A sequence of user themes.
 247        """
 248        data = await self.rest.fetch_user_themes()
 249
 250        return self.factory.deserialize_user_themes(data)
 251
 252    async def fetch_hard_types(
 253        self,
 254        credential: int,
 255        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
 256        /,
 257    ) -> user.HardLinkedMembership:
 258        """Gets any hard linked membership given a credential.
 259        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
 260        Cross Save aware.
 261
 262        Parameters
 263        ----------
 264        credential: `int`
 265            A valid SteamID64
 266        type: `aiobungie.CredentialType`
 267            The credential type. This must not be changed
 268            Since its only credential that works "currently"
 269
 270        Returns
 271        -------
 272        `aiobungie.crates.user.HardLinkedMembership`
 273            Information about the hard linked data.
 274        """
 275
 276        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
 277
 278        return user.HardLinkedMembership(
 279            id=int(payload["membershipId"]),
 280            type=enums.MembershipType(payload["membershipType"]),
 281            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
 282        )
 283
 284    async def fetch_membership_from_id(
 285        self,
 286        id: int,
 287        /,
 288        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 289    ) -> user.User:
 290        """Fetch Bungie user's memberships from their id.
 291
 292        Notes
 293        -----
 294        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
 295        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
 296        see `aiobungie.crates.user.DestinyMembership` for more details.
 297        * If you only want the bungie user. Consider using `Client.fetch_user` method.
 298
 299        Parameters
 300        ----------
 301        id : `int`
 302            The user's id.
 303        type : `aiobungie.MembershipType`
 304            The user's membership type.
 305
 306        Returns
 307        -------
 308        `aiobungie.crates.User`
 309            A Bungie user with their membership types.
 310
 311        Raises
 312        ------
 313        aiobungie.NotFound
 314            The requested user was not found.
 315        """
 316        payload = await self.rest.fetch_membership_from_id(id, type)
 317
 318        return self.factory.deserialize_user(payload)
 319
 320    async def fetch_user_credentials(
 321        self, access_token: str, membership_id: int, /
 322    ) -> collections.Sequence[user.UserCredentials]:
 323        """Fetch an array of credential types attached to the requested account.
 324
 325        .. note::
 326            This method require OAuth2 Bearer access token.
 327
 328        Parameters
 329        ----------
 330        access_token : `str`
 331            The bearer access token associated with the bungie account.
 332        membership_id : `int`
 333            The id of the membership to return.
 334
 335        Returns
 336        -------
 337        `collections.Sequence[aiobungie.crates.UserCredentials]`
 338            A sequence of the attached user credentials.
 339
 340        Raises
 341        ------
 342        `aiobungie.Unauthorized`
 343            The access token was wrong or no access token passed.
 344        """
 345        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
 346
 347        return self.factory.deserialize_user_credentials(resp)
 348
 349    # * Destiny 2.
 350
 351    async def fetch_profile(
 352        self,
 353        member_id: int,
 354        type: typedefs.IntAnd[enums.MembershipType],
 355        components: list[enums.ComponentType],
 356        auth: typing.Optional[str] = None,
 357    ) -> components.Component:
 358        """
 359        Fetch a bungie profile passing components to the request.
 360
 361        Parameters
 362        ----------
 363        member_id: `int`
 364            The member's id.
 365        type: `aiobungie.MembershipType`
 366            A valid membership type.
 367        components : `list[aiobungie.ComponentType]`
 368            List of profile components to collect and return.
 369
 370        Other Parameters
 371        ----------------
 372        auth : `typing.Optional[str]`
 373            A Bearer access_token to make the request with.
 374            This is optional and limited to components that only requires an Authorization token.
 375
 376        Returns
 377        --------
 378        `aiobungie.crates.Component`
 379            A Destiny 2 player profile with its components.
 380            Only passed components will be available if they exists. Otherwise they will be `None`
 381
 382        Raises
 383        ------
 384        `aiobungie.MembershipTypeError`
 385            The provided membership type was invalid.
 386        """
 387        data = await self.rest.fetch_profile(member_id, type, components, auth)
 388        return self.factory.deserialize_components(data)
 389
 390    async def fetch_linked_profiles(
 391        self,
 392        member_id: int,
 393        member_type: typedefs.IntAnd[enums.MembershipType],
 394        /,
 395        *,
 396        all: bool = False,
 397    ) -> profile.LinkedProfile:
 398        """Returns a summary information about all profiles linked to the requested member.
 399
 400        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
 401
 402        .. note::
 403            It will only return linked accounts whose linkages you are allowed to view.
 404
 405        Parameters
 406        ----------
 407        member_id : `int`
 408            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
 409        member_type : `aiobungie.MembershipType`
 410            The type for the membership whose linked Destiny account you want to return.
 411
 412        Other Parameters
 413        ----------------
 414        all : `bool`
 415            If provided and set to `True`, All memberships regardless
 416            of whether they're obscured by overrides will be returned,
 417
 418            If provided and set to `False`, Only available memberships will be returned.
 419            The default for this is `False`.
 420
 421        Returns
 422        -------
 423        `aiobungie.crates.profile.LinkedProfile`
 424            A linked profile object.
 425        """
 426        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
 427
 428        return self.factory.deserialize_linked_profiles(resp)
 429
 430    async def fetch_player(
 431        self,
 432        name: str,
 433        code: int,
 434        /,
 435        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 436    ) -> collections.Sequence[user.DestinyMembership]:
 437        """Fetch a Destiny 2 player's memberships.
 438
 439        Parameters
 440        -----------
 441        name: `str`
 442            The unique Bungie player name.
 443        code : `int`
 444            The unique Bungie display name code.
 445        type: `aiobungie.internal.enums.MembershipType`
 446            The player's membership type, e,g. XBOX, STEAM, PSN
 447
 448        Returns
 449        --------
 450        `collections.Sequence[aiobungie.crates.DestinyMembership]`
 451            A sequence of the found Destiny 2 player memberships.
 452            An empty sequence will be returned if no one found.
 453
 454        Raises
 455        ------
 456        `aiobungie.MembershipTypeError`
 457            The provided membership type was invalid.
 458        """
 459        resp = await self.rest.fetch_player(name, code, type)
 460
 461        return self.factory.deserialize_destiny_memberships(resp)
 462
 463    async def fetch_character(
 464        self,
 465        member_id: int,
 466        membership_type: typedefs.IntAnd[enums.MembershipType],
 467        character_id: int,
 468        components: list[enums.ComponentType],
 469        auth: typing.Optional[str] = None,
 470    ) -> components.CharacterComponent:
 471        """Fetch a Destiny 2 character.
 472
 473        Parameters
 474        ----------
 475        member_id: `int`
 476            A valid bungie member id.
 477        character_id: `int`
 478            The Destiny character id to retrieve.
 479        membership_type: `aiobungie.internal.enums.MembershipType`
 480            The member's membership type.
 481        components: `list[aiobungie.ComponentType]`
 482            Multiple arguments of character components to collect and return.
 483
 484        Other Parameters
 485        ----------------
 486        auth : `typing.Optional[str]`
 487            A Bearer access_token to make the request with.
 488            This is optional and limited to components that only requires an Authorization token.
 489
 490        Returns
 491        -------
 492        `aiobungie.crates.CharacterComponent`
 493            A Bungie character component.
 494
 495        `aiobungie.MembershipTypeError`
 496            The provided membership type was invalid.
 497        """
 498        resp = await self.rest.fetch_character(
 499            member_id, membership_type, character_id, components, auth
 500        )
 501
 502        return self.factory.deserialize_character_component(resp)
 503
 504    async def fetch_unique_weapon_history(
 505        self,
 506        membership_id: int,
 507        character_id: int,
 508        membership_type: typedefs.IntAnd[enums.MembershipType],
 509    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
 510        """Fetch details about unique weapon usage for a character. Includes all exotics.
 511
 512        Parameters
 513        ----------
 514        membership_id : `int`
 515            The Destiny user membership id.
 516        character_id : `int`
 517            The character id to retrieve.
 518        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 519            The Destiny user's membership type.
 520
 521        Returns
 522        -------
 523        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
 524            A sequence of the weapon's extended values.
 525        """
 526        resp = await self._rest.fetch_unique_weapon_history(
 527            membership_id, character_id, membership_type
 528        )
 529
 530        return [
 531            self._factory.deserialize_extended_weapon_values(weapon)
 532            for weapon in resp["weapons"]
 533        ]
 534
 535    # * Destiny 2 Activities.
 536
 537    async def fetch_activities(
 538        self,
 539        member_id: int,
 540        character_id: int,
 541        mode: typedefs.IntAnd[enums.GameMode],
 542        *,
 543        membership_type: typedefs.IntAnd[
 544            enums.MembershipType
 545        ] = enums.MembershipType.ALL,
 546        page: int = 0,
 547        limit: int = 250,
 548    ) -> iterators.FlatIterator[activity.Activity]:
 549        """Fetch a Destiny 2 activity for the specified character id.
 550
 551        Parameters
 552        ----------
 553        member_id: `int`
 554            The user id that starts with `4611`.
 555        character_id: `int`
 556            The id of the character to retrieve the activities for.
 557        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
 558            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
 559
 560        Other Parameters
 561        ----------------
 562        membership_type: `aiobungie.internal.enums.MembershipType`
 563            The Member ship type, if nothing was passed than it will return all.
 564        page: int
 565            The page number. Default is `0`
 566        limit: int
 567            Limit the returned result. Default is `250`.
 568
 569        Returns
 570        -------
 571        `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]`
 572            An iterator of the player's activities.
 573
 574        Raises
 575        ------
 576        `aiobungie.MembershipTypeError`
 577            The provided membership type was invalid.
 578        """
 579        resp = await self.rest.fetch_activities(
 580            member_id,
 581            character_id,
 582            mode,
 583            membership_type=membership_type,
 584            page=page,
 585            limit=limit,
 586        )
 587
 588        return self.factory.deserialize_activities(resp)
 589
 590    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
 591        """Fetch a post activity details.
 592
 593        Parameters
 594        ----------
 595        instance_id: `int`
 596            The activity instance id.
 597
 598        Returns
 599        -------
 600        `aiobungie.crates.PostActivity`
 601           A post activity object.
 602        """
 603        resp = await self.rest.fetch_post_activity(instance_id)
 604
 605        return self.factory.deserialize_post_activity(resp)
 606
 607    async def fetch_aggregated_activity_stats(
 608        self,
 609        character_id: int,
 610        membership_id: int,
 611        membership_type: typedefs.IntAnd[enums.MembershipType],
 612    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
 613        """Fetch aggregated activity stats for a character.
 614
 615        Parameters
 616        ----------
 617        character_id: `int`
 618            The id of the character to retrieve the activities for.
 619        membership_id: `int`
 620            The id of the user that started with `4611`.
 621        membership_type: `aiobungie.internal.enums.MembershipType`
 622            The Member ship type.
 623
 624        Returns
 625        -------
 626        `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]`
 627            An iterator of the player's activities.
 628
 629        Raises
 630        ------
 631        `aiobungie.MembershipTypeError`
 632            The provided membership type was invalid.
 633        """
 634        resp = await self.rest.fetch_aggregated_activity_stats(
 635            character_id, membership_id, membership_type
 636        )
 637
 638        return self.factory.deserialize_aggregated_activities(resp)
 639
 640    # * Destiny 2 Clans or GroupsV2.
 641
 642    async def fetch_clan_from_id(
 643        self,
 644        id: int,
 645        /,
 646        access_token: typing.Optional[str] = None,
 647    ) -> clans.Clan:
 648        """Fetch a Bungie Clan by its id.
 649
 650        Parameters
 651        -----------
 652        id: `int`
 653            The clan id.
 654
 655        Returns
 656        --------
 657        `aiobungie.crates.Clan`
 658            An Bungie clan.
 659
 660        Raises
 661        ------
 662        `aiobungie.NotFound`
 663            The clan was not found.
 664        """
 665        resp = await self.rest.fetch_clan_from_id(id, access_token)
 666
 667        return self.factory.deserialize_clan(resp)
 668
 669    async def fetch_clan(
 670        self,
 671        name: str,
 672        /,
 673        access_token: typing.Optional[str] = None,
 674        *,
 675        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 676    ) -> clans.Clan:
 677        """Fetch a Clan by its name.
 678        This method will return the first clan found with given name.
 679
 680        Parameters
 681        ----------
 682        name: `str`
 683            The clan name
 684
 685        Other Parameters
 686        ----------------
 687        access_token : `typing.Optional[str]`
 688            An optional access token to make the request with.
 689
 690            If the token was bound to a member of the clan,
 691            This field `aiobungie.crates.Clan.current_user_membership` will be available
 692            and will return the membership of the user who made this request.
 693        type : `aiobungie.GroupType`
 694            The group type, Default is aiobungie.GroupType.CLAN.
 695
 696        Returns
 697        -------
 698        `aiobungie.crates.Clan`
 699            A Bungie clan.
 700
 701        Raises
 702        ------
 703        `aiobungie.NotFound`
 704            The clan was not found.
 705        """
 706        resp = await self.rest.fetch_clan(name, access_token, type=type)
 707
 708        return self.factory.deserialize_clan(resp)
 709
 710    async def fetch_clan_conversations(
 711        self, clan_id: int, /
 712    ) -> collections.Sequence[clans.ClanConversation]:
 713        """Fetch the conversations/chat channels of the given clan id.
 714
 715        Parameters
 716        ----------
 717        clan_id : `int`
 718            The clan id.
 719
 720        Returns
 721        `collections.Sequence[aiobungie.crates.ClanConversation]`
 722            A sequence of the clan chat channels.
 723        """
 724        resp = await self.rest.fetch_clan_conversations(clan_id)
 725
 726        return self.factory.deserialize_clan_conversations(resp)
 727
 728    async def fetch_clan_admins(
 729        self, clan_id: int, /
 730    ) -> iterators.FlatIterator[clans.ClanMember]:
 731        """Fetch the clan founder and admins.
 732
 733        Parameters
 734        ----------
 735        clan_id : `int`
 736            The clan id.
 737
 738        Returns
 739        -------
 740        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
 741            An iterator over the found clan admins and founder.
 742
 743        Raises
 744        ------
 745        `aiobungie.NotFound`
 746            The requested clan was not found.
 747        """
 748        resp = await self.rest.fetch_clan_admins(clan_id)
 749
 750        return self.factory.deserialize_clan_members(resp)
 751
 752    async def fetch_groups_for_member(
 753        self,
 754        member_id: int,
 755        member_type: typedefs.IntAnd[enums.MembershipType],
 756        /,
 757        *,
 758        filter: int = 0,
 759        group_type: enums.GroupType = enums.GroupType.CLAN,
 760    ) -> collections.Sequence[clans.GroupMember]:
 761        """Fetch information about the groups that a given member has joined.
 762
 763        Parameters
 764        ----------
 765        member_id : `int`
 766            The member's id
 767        member_type : `aiobungie.MembershipType`
 768            The member's membership type.
 769
 770        Other Parameters
 771        ----------------
 772        filter : `int`
 773            Filter apply to list of joined groups. This Default to `0`
 774        group_type : `aiobungie.GroupType`
 775            The group's type.
 776            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 777
 778        Returns
 779        -------
 780        `collections.Sequence[aiobungie.crates.GroupMember]`
 781            A sequence of joined groups for the fetched member.
 782        """
 783        resp = await self.rest.fetch_groups_for_member(
 784            member_id, member_type, filter=filter, group_type=group_type
 785        )
 786
 787        return [
 788            self.factory.deserialize_group_member(group) for group in resp["results"]
 789        ]
 790
 791    async def fetch_potential_groups_for_member(
 792        self,
 793        member_id: int,
 794        member_type: typedefs.IntAnd[enums.MembershipType],
 795        /,
 796        *,
 797        filter: int = 0,
 798        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 799    ) -> collections.Sequence[clans.GroupMember]:
 800        """Fetch the potential groups for a clan member.
 801
 802        Parameters
 803        ----------
 804        member_id : `int`
 805            The member's id
 806        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 807            The member's membership type.
 808
 809        Other Parameters
 810        ----------------
 811        filter : `int`
 812            Filter apply to list of joined groups. This Default to `0`
 813        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
 814            The group's type.
 815            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 816
 817        Returns
 818        -------
 819        `collections.Sequence[aiobungie.crates.GroupMember]`
 820            A sequence of joined potential groups for the fetched member.
 821        """
 822        resp = await self.rest.fetch_potential_groups_for_member(
 823            member_id, member_type, filter=filter, group_type=group_type
 824        )
 825
 826        return [
 827            self.factory.deserialize_group_member(group) for group in resp["results"]
 828        ]
 829
 830    async def fetch_clan_members(
 831        self,
 832        clan_id: int,
 833        /,
 834        *,
 835        name: typing.Optional[str] = None,
 836        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 837    ) -> iterators.FlatIterator[clans.ClanMember]:
 838        """Fetch Bungie clan members.
 839
 840        Parameters
 841        ----------
 842        clan_id : `int`
 843            The clans id
 844
 845        Other Parameters
 846        ----------------
 847        name : `typing.Optional[str]`
 848            If provided, Only players matching this name will be returned.
 849        type : `aiobungie.MembershipType`
 850            An optional clan member's membership type.
 851            This parameter is used to filter the returned results
 852            by the provided membership, For an example XBox memberships only,
 853            Otherwise will return all memberships.
 854
 855        Returns
 856        -------
 857        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
 858            An iterator over the bungie clan members.
 859
 860        Raises
 861        ------
 862        `aiobungie.NotFound`
 863            The clan was not found.
 864        """
 865        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
 866
 867        return self.factory.deserialize_clan_members(resp)
 868
 869    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
 870        """Fetch the clan banners.
 871
 872        Returns
 873        -------
 874        `collections.Sequence[aiobungie.crates.ClanBanner]`
 875            A sequence of the clan banners.
 876        """
 877        resp = await self.rest.fetch_clan_banners()
 878
 879        return self.factory.deserialize_clan_banners(resp)
 880
 881    # This method is required to be here since it deserialize the clan.
 882    async def kick_clan_member(
 883        self,
 884        access_token: str,
 885        /,
 886        group_id: int,
 887        membership_id: int,
 888        membership_type: typedefs.IntAnd[enums.MembershipType],
 889    ) -> clans.Clan:
 890        """Kick a member from the clan.
 891
 892        .. note::
 893            This request requires OAuth2: oauth2: `AdminGroups` scope.
 894
 895        Parameters
 896        ----------
 897        access_token : `str`
 898            The bearer access token associated with the bungie account.
 899        group_id: `int`
 900            The group id.
 901        membership_id : `int`
 902            The member id to kick.
 903        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 904            The member's membership type.
 905
 906        Returns
 907        -------
 908        `aiobungie.crates.clan.Clan`
 909            The clan that the member was kicked from.
 910        """
 911        resp = await self.rest.kick_clan_member(
 912            access_token,
 913            group_id=group_id,
 914            membership_id=membership_id,
 915            membership_type=membership_type,
 916        )
 917
 918        return self.factory.deserialize_clan(resp)
 919
 920    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
 921        """Fetch a Bungie clan's weekly reward state.
 922
 923        Parameters
 924        ----------
 925        clan_id : `int`
 926            The clan's id.
 927
 928        Returns
 929        -------
 930        `aiobungie.crates.Milestone`
 931            A runtime status of the clan's milestone data.
 932        """
 933
 934        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
 935
 936        return self.factory.deserialize_milestone(resp)
 937
 938    # * Destiny 2 Entities aka Definitions.
 939
 940    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
 941        """Fetch a static inventory item entity given a its hash.
 942
 943        Parameters
 944        ----------
 945        hash: `int`
 946            Inventory item's hash.
 947
 948        Returns
 949        -------
 950        `aiobungie.crates.InventoryEntity`
 951            A bungie inventory item.
 952        """
 953        resp = await self.rest.fetch_inventory_item(hash)
 954
 955        return self.factory.deserialize_inventory_entity(resp)
 956
 957    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
 958        """Fetch a Destiny objective entity given a its hash.
 959
 960        Parameters
 961        ----------
 962        hash: `int`
 963            objective's hash.
 964
 965        Returns
 966        -------
 967        `aiobungie.crates.ObjectiveEntity`
 968            An objective entity item.
 969        """
 970        resp = await self.rest.fetch_objective_entity(hash)
 971
 972        return self.factory.deserialize_objective_entity(resp)
 973
 974    async def search_entities(
 975        self, name: str, entity_type: str, *, page: int = 0
 976    ) -> iterators.FlatIterator[entity.SearchableEntity]:
 977        """Search for Destiny2 entities given a name and its type.
 978
 979        Parameters
 980        ----------
 981        name : `str`
 982            The name of the entity, i.e., Thunderlord, One thousand voices.
 983        entity_type : `str`
 984            The type of the entity, AKA Definition,
 985            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
 986
 987        Other Parameters
 988        ----------------
 989        page : `int`
 990            An optional page to return. Default to 0.
 991
 992        Returns
 993        -------
 994        `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]`
 995            An iterator over the found results matching the provided name.
 996        """
 997        resp = await self.rest.search_entities(name, entity_type, page=page)
 998
 999        return self.factory.deserialize_inventory_results(resp)
1000
1001    # Fireteams
1002
1003    async def fetch_fireteams(
1004        self,
1005        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1006        *,
1007        platform: typedefs.IntAnd[
1008            fireteams.FireteamPlatform
1009        ] = fireteams.FireteamPlatform.ANY,
1010        language: typing.Union[
1011            fireteams.FireteamLanguage, str
1012        ] = fireteams.FireteamLanguage.ALL,
1013        date_range: int = 0,
1014        page: int = 0,
1015        slots_filter: int = 0,
1016    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1017        """Fetch public Bungie fireteams with open slots.
1018
1019        Parameters
1020        ----------
1021        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1022            The fireteam activity type.
1023
1024        Other Parameters
1025        ----------------
1026        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1027            If this is provided. Then the results will be filtered with the given platform.
1028            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1029        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1030            A locale language to filter the used language in that fireteam.
1031            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1032        date_range : `int`
1033            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1034        page : `int`
1035            The page number. By default its `0` which returns all available activities.
1036        slots_filter : `int`
1037            Filter the returned fireteams based on available slots. Default is `0`
1038
1039        Returns
1040        -------
1041        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1042            A sequence of `aiobungie.crates.Fireteam` or `None`.
1043        """
1044
1045        resp = await self.rest.fetch_fireteams(
1046            activity_type,
1047            platform=platform,
1048            language=language,
1049            date_range=date_range,
1050            page=page,
1051            slots_filter=slots_filter,
1052        )
1053
1054        return self.factory.deserialize_fireteams(resp)
1055
1056    async def fetch_avaliable_clan_fireteams(
1057        self,
1058        access_token: str,
1059        group_id: int,
1060        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1061        *,
1062        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1063        language: typing.Union[fireteams.FireteamLanguage, str],
1064        date_range: int = 0,
1065        page: int = 0,
1066        public_only: bool = False,
1067        slots_filter: int = 0,
1068    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1069        """Fetch a clan's fireteams with open slots.
1070
1071        .. note::
1072            This method requires OAuth2: ReadGroups scope.
1073
1074        Parameters
1075        ----------
1076        access_token : `str`
1077            The bearer access token associated with the bungie account.
1078        group_id : `int`
1079            The group/clan id of the fireteam.
1080        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1081            The fireteam activity type.
1082
1083        Other Parameters
1084        ----------------
1085        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1086            If this is provided. Then the results will be filtered with the given platform.
1087            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1088        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1089            A locale language to filter the used language in that fireteam.
1090            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1091        date_range : `int`
1092            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1093        page : `int`
1094            The page number. By default its `0` which returns all available activities.
1095        public_only: `bool`
1096            If set to True, Then only public fireteams will be returned.
1097        slots_filter : `int`
1098            Filter the returned fireteams based on available slots. Default is `0`
1099
1100        Returns
1101        -------
1102        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1103            A sequence of  fireteams found in the clan.
1104            `None` will be returned if nothing was found.
1105        """
1106        resp = await self.rest.fetch_avaliable_clan_fireteams(
1107            access_token,
1108            group_id,
1109            activity_type,
1110            platform=platform,
1111            language=language,
1112            date_range=date_range,
1113            page=page,
1114            public_only=public_only,
1115            slots_filter=slots_filter,
1116        )
1117
1118        return self.factory.deserialize_fireteams(resp)
1119
1120    async def fetch_clan_fireteam(
1121        self, access_token: str, fireteam_id: int, group_id: int
1122    ) -> fireteams.AvailableFireteam:
1123        """Fetch a specific clan fireteam.
1124
1125        .. note::
1126            This method requires OAuth2: ReadGroups scope.
1127
1128        Parameters
1129        ----------
1130        access_token : `str`
1131            The bearer access token associated with the bungie account.
1132        group_id : `int`
1133            The group/clan id to fetch the fireteam from.
1134        fireteam_id : `int`
1135            The fireteam id to fetch.
1136
1137        Returns
1138        -------
1139        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1140            A sequence of available fireteams objects if exists. else `None` will be returned.
1141        """
1142        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1143
1144        return self.factory.deserialize_available_fireteams(
1145            resp, no_results=True
1146        )  # type: ignore[return-value]
1147
1148    async def fetch_my_clan_fireteams(
1149        self,
1150        access_token: str,
1151        group_id: int,
1152        *,
1153        include_closed: bool = True,
1154        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1155        language: typing.Union[fireteams.FireteamLanguage, str],
1156        filtered: bool = True,
1157        page: int = 0,
1158    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1159        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1160
1161        .. note::
1162            This method requires OAuth2: ReadGroups scope.
1163
1164        Parameters
1165        ----------
1166        access_token : str
1167            The bearer access token associated with the bungie account.
1168        group_id : int
1169            The group/clan id to fetch.
1170
1171        Other Parameters
1172        ----------------
1173        include_closed : bool
1174            If provided and set to True, It will also return closed fireteams.
1175            If provided and set to False, It will only return public fireteams. Default is True.
1176        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1177            If this is provided. Then the results will be filtered with the given platform.
1178            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1179        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1180            A locale language to filter the used language in that fireteam.
1181            Defaults to aiobungie.crates.FireteamLanguage.ALL
1182        filtered : bool
1183            If set to True, it will filter by clan. Otherwise not. Default is True.
1184        page : int
1185            The page number. By default its 0 which returns all available activities.
1186
1187        Returns
1188        -------
1189        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1190            A sequence of available fireteams objects if exists. else `None` will be returned.
1191        """
1192        resp = await self.rest.fetch_my_clan_fireteams(
1193            access_token,
1194            group_id,
1195            include_closed=include_closed,
1196            platform=platform,
1197            language=language,
1198            filtered=filtered,
1199            page=page,
1200        )
1201
1202        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]
1203
1204    # Friends and social.
1205
1206    async def fetch_friends(
1207        self, access_token: str, /
1208    ) -> collections.Sequence[friends.Friend]:
1209        """Fetch bungie friend list.
1210
1211        .. note::
1212            This requests OAuth2: ReadUserData scope.
1213
1214        Parameters
1215        -----------
1216        access_token : `str`
1217            The bearer access token associated with the bungie account.
1218
1219        Returns
1220        -------
1221        `collections.Sequence[aiobungie.crates.Friend]`
1222            A sequence of the friends associated with that access token.
1223        """
1224
1225        resp = await self.rest.fetch_friends(access_token)
1226
1227        return self.factory.deserialize_friends(resp)
1228
1229    async def fetch_friend_requests(
1230        self, access_token: str, /
1231    ) -> friends.FriendRequestView:
1232        """Fetch pending bungie friend requests queue.
1233
1234        .. note::
1235            This requests OAuth2: ReadUserData scope.
1236
1237        Parameters
1238        -----------
1239        access_token : `str`
1240            The bearer access token associated with the bungie account.
1241
1242        Returns
1243        -------
1244        `aiobungie.crates.FriendRequestView`
1245            A friend requests view of that associated access token.
1246        """
1247
1248        resp = await self.rest.fetch_friend_requests(access_token)
1249
1250        return self.factory.deserialize_friend_requests(resp)
1251
1252    # Applications and Developer portal.
1253
1254    async def fetch_application(self, appid: int, /) -> application.Application:
1255        """Fetch a Bungie application.
1256
1257        Parameters
1258        -----------
1259        appid: `int`
1260            The application id.
1261
1262        Returns
1263        --------
1264        `aiobungie.crates.Application`
1265            A Bungie application.
1266        """
1267        resp = await self.rest.fetch_application(appid)
1268
1269        return self.factory.deserialize_app(resp)
1270
1271    # Milestones
1272
1273    async def fetch_public_milestone_content(
1274        self, milestone_hash: int, /
1275    ) -> milestones.MilestoneContent:
1276        """Fetch the milestone content given its hash.
1277
1278        Parameters
1279        ----------
1280        milestone_hash : `int`
1281            The milestone hash.
1282
1283        Returns
1284        -------
1285        `aiobungie.crates.milestones.MilestoneContent`
1286            A milestone content object.
1287        """
1288        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1289
1290        return self.factory.deserialize_public_milestone_content(resp)

Standard Bungie API client application.

This client deserialize the REST JSON responses using aiobungie.Factory and returns aiobungie.crates Python object implementations of the responses.

A aiobungie.RESTClient REST client can also be used alone for low-level concepts.

Example
import aiobungie

client = aiobungie.Client('...')

async def main():
    async with client.rest:
        user = await client.fetch_current_user_memberships('...')
        print(user)
Parameters
  • token (str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
  • rest_client (aiobungie.interfaces.RESTInterface | None): An optional rest client instance you can pass. If set to None then the client will use the default instance.
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • max_ratelimit_retries (int): The max retries number to retry if the request hit a 429 status code. Defaults to 3.
  • client_secret (str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
Client( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, rest_client: Optional[aiobungie.interfaces.rest.RESTInterface] = None, max_retries: int = 4, max_ratelimit_retries: int = 3)
107    def __init__(
108        self,
109        token: str,
110        /,
111        client_secret: typing.Optional[str] = None,
112        client_id: typing.Optional[int] = None,
113        *,
114        rest_client: typing.Optional[interfaces.RESTInterface] = None,
115        max_retries: int = 4,
116        max_ratelimit_retries: int = 3,
117    ) -> None:
118
119        self._client_secret = client_secret
120        self._client_id = client_id
121
122        self._rest = (
123            rest_client
124            if rest_client is not None
125            else rest_.RESTClient(
126                token,
127                client_secret,
128                client_id,
129                max_retries=max_retries,
130                max_ratelimit_retries=max_ratelimit_retries,
131            )
132        )
133
134        self._factory = factory_.Factory(self)

Returns the marshalling factory for the client.

rest: aiobungie.interfaces.rest.RESTInterface

Returns the REST client for the this client.

request: aiobungie.Client

A readonly ClientApp instance used for external requests.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

def run( self, future: collections.abc.Coroutine[typing.Any, None, None], debug: bool = False) -> None:
152    def run(
153        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
154    ) -> None:
155        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
156        try:
157            if not loop.is_running():
158                loop.set_debug(debug)
159                loop.run_until_complete(future)
160
161        except Exception as exc:
162            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
163
164        except KeyboardInterrupt:
165            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
166            return

Runs a coroutine function until its complete.

This is equivalent to asyncio.get_event_loop().run_until_complete(...)

Parameters
  • future (collections.Coroutine[None, None, None]): A coroutine object.
  • debug (bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
    await fetch(...)

# Run the coroutine.
client.run(main())
async def fetch_current_user_memberships(self, access_token: str, /) -> aiobungie.crates.user.User:
170    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
171        """Fetch and return a user object of the bungie net user associated with account.
172
173        .. warning::
174            This method requires OAuth2 scope and a Bearer access token.
175
176        Parameters
177        ----------
178        access_token : `str`
179            A valid Bearer access token for the authorization.
180
181        Returns
182        -------
183        `aiobungie.crates.user.User`
184            A user object includes the Destiny memberships and Bungie.net user.
185        """
186        resp = await self.rest.fetch_current_user_memberships(access_token)
187
188        return self.factory.deserialize_user(resp)

Fetch and return a user object of the bungie net user associated with account.

This method requires OAuth2 scope and a Bearer access token.

Parameters
  • access_token (str): A valid Bearer access token for the authorization.
Returns
  • aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
async def fetch_bungie_user(self, id: int, /) -> aiobungie.crates.user.BungieUser:
190    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
191        """Fetch a Bungie user by their BungieNet id.
192
193        .. note::
194            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
195            for other memberships.
196
197        Parameters
198        ----------
199        id: `int`
200            The user id.
201
202        Returns
203        -------
204        `aiobungie.crates.user.BungieUser`
205            A Bungie user.
206
207        Raises
208        ------
209        `aiobungie.error.NotFound`
210            The user was not found.
211        """
212        payload = await self.rest.fetch_bungie_user(id)
213
214        return self.factory.deserialize_bungie_user(payload)

Fetch a Bungie user by their BungieNet id.

This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id for other memberships.

Parameters
  • id (int): The user id.
Returns
  • aiobungie.crates.user.BungieUser: A Bungie user.
Raises
async def search_users( self, name: str, /) -> aiobungie.FlatIterator[aiobungie.crates.user.SearchableDestinyUser]:
216    async def search_users(
217        self, name: str, /
218    ) -> iterators.FlatIterator[user.SearchableDestinyUser]:
219        """Search for players and return all players that matches the same name.
220
221        Parameters
222        ----------
223        name : `buildins.str`
224            The user name.
225
226        Returns
227        -------
228        `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]`
229            A sequence of destiny memberships.
230        """
231        payload = await self.rest.search_users(name)
232
233        return iterators.FlatIterator(
234            [
235                self.factory.deserialize_searched_user(user)
236                for user in payload["searchResults"]
237            ]
238        )

Search for players and return all players that matches the same name.

Parameters
  • name (buildins.str): The user name.
Returns
async def fetch_user_themes(self) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
240    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
241        """Fetch all available user themes.
242
243        Returns
244        -------
245        `collections.Sequence[aiobungie.crates.user.UserThemes]`
246            A sequence of user themes.
247        """
248        data = await self.rest.fetch_user_themes()
249
250        return self.factory.deserialize_user_themes(data)

Fetch all available user themes.

Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
async def fetch_hard_types( self, credential: int, type: Union[int, aiobungie.CredentialType] = <CredentialType.STEAMID: 12>, /) -> aiobungie.crates.user.HardLinkedMembership:
252    async def fetch_hard_types(
253        self,
254        credential: int,
255        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
256        /,
257    ) -> user.HardLinkedMembership:
258        """Gets any hard linked membership given a credential.
259        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
260        Cross Save aware.
261
262        Parameters
263        ----------
264        credential: `int`
265            A valid SteamID64
266        type: `aiobungie.CredentialType`
267            The credential type. This must not be changed
268            Since its only credential that works "currently"
269
270        Returns
271        -------
272        `aiobungie.crates.user.HardLinkedMembership`
273            Information about the hard linked data.
274        """
275
276        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
277
278        return user.HardLinkedMembership(
279            id=int(payload["membershipId"]),
280            type=enums.MembershipType(payload["membershipType"]),
281            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
282        )

Gets any hard linked membership given a credential. Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
  • credential (int): A valid SteamID64
  • type (aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
  • aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
async def fetch_membership_from_id( self, id: int, /, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.crates.user.User:
284    async def fetch_membership_from_id(
285        self,
286        id: int,
287        /,
288        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
289    ) -> user.User:
290        """Fetch Bungie user's memberships from their id.
291
292        Notes
293        -----
294        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
295        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
296        see `aiobungie.crates.user.DestinyMembership` for more details.
297        * If you only want the bungie user. Consider using `Client.fetch_user` method.
298
299        Parameters
300        ----------
301        id : `int`
302            The user's id.
303        type : `aiobungie.MembershipType`
304            The user's membership type.
305
306        Returns
307        -------
308        `aiobungie.crates.User`
309            A Bungie user with their membership types.
310
311        Raises
312        ------
313        aiobungie.NotFound
314            The requested user was not found.
315        """
316        payload = await self.rest.fetch_membership_from_id(id, type)
317
318        return self.factory.deserialize_user(payload)

Fetch Bungie user's memberships from their id.

Notes
  • This returns both BungieNet membership and a sequence of the player's DestinyMemberships Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, see aiobungie.crates.user.DestinyMembership for more details.
  • If you only want the bungie user. Consider using Client.fetch_user method.
Parameters
Returns
Raises
async def fetch_user_credentials( self, access_token: str, membership_id: int, /) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
320    async def fetch_user_credentials(
321        self, access_token: str, membership_id: int, /
322    ) -> collections.Sequence[user.UserCredentials]:
323        """Fetch an array of credential types attached to the requested account.
324
325        .. note::
326            This method require OAuth2 Bearer access token.
327
328        Parameters
329        ----------
330        access_token : `str`
331            The bearer access token associated with the bungie account.
332        membership_id : `int`
333            The id of the membership to return.
334
335        Returns
336        -------
337        `collections.Sequence[aiobungie.crates.UserCredentials]`
338            A sequence of the attached user credentials.
339
340        Raises
341        ------
342        `aiobungie.Unauthorized`
343            The access token was wrong or no access token passed.
344        """
345        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
346
347        return self.factory.deserialize_user_credentials(resp)

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def fetch_profile( self, member_id: int, type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.Component:
351    async def fetch_profile(
352        self,
353        member_id: int,
354        type: typedefs.IntAnd[enums.MembershipType],
355        components: list[enums.ComponentType],
356        auth: typing.Optional[str] = None,
357    ) -> components.Component:
358        """
359        Fetch a bungie profile passing components to the request.
360
361        Parameters
362        ----------
363        member_id: `int`
364            The member's id.
365        type: `aiobungie.MembershipType`
366            A valid membership type.
367        components : `list[aiobungie.ComponentType]`
368            List of profile components to collect and return.
369
370        Other Parameters
371        ----------------
372        auth : `typing.Optional[str]`
373            A Bearer access_token to make the request with.
374            This is optional and limited to components that only requires an Authorization token.
375
376        Returns
377        --------
378        `aiobungie.crates.Component`
379            A Destiny 2 player profile with its components.
380            Only passed components will be available if they exists. Otherwise they will be `None`
381
382        Raises
383        ------
384        `aiobungie.MembershipTypeError`
385            The provided membership type was invalid.
386        """
387        data = await self.rest.fetch_profile(member_id, type, components, auth)
388        return self.factory.deserialize_components(data)

Fetch a bungie profile passing components to the request.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
  • aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will be None
Raises
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, all: bool = False) -> aiobungie.crates.profile.LinkedProfile:
390    async def fetch_linked_profiles(
391        self,
392        member_id: int,
393        member_type: typedefs.IntAnd[enums.MembershipType],
394        /,
395        *,
396        all: bool = False,
397    ) -> profile.LinkedProfile:
398        """Returns a summary information about all profiles linked to the requested member.
399
400        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
401
402        .. note::
403            It will only return linked accounts whose linkages you are allowed to view.
404
405        Parameters
406        ----------
407        member_id : `int`
408            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
409        member_type : `aiobungie.MembershipType`
410            The type for the membership whose linked Destiny account you want to return.
411
412        Other Parameters
413        ----------------
414        all : `bool`
415            If provided and set to `True`, All memberships regardless
416            of whether they're obscured by overrides will be returned,
417
418            If provided and set to `False`, Only available memberships will be returned.
419            The default for this is `False`.
420
421        Returns
422        -------
423        `aiobungie.crates.profile.LinkedProfile`
424            A linked profile object.
425        """
426        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
427
428        return self.factory.deserialize_linked_profiles(resp)

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
  • member_id (int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
  • member_type (aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether they're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
  • aiobungie.crates.profile.LinkedProfile: A linked profile object.
async def fetch_player( self, name: str, code: int, /, type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
430    async def fetch_player(
431        self,
432        name: str,
433        code: int,
434        /,
435        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
436    ) -> collections.Sequence[user.DestinyMembership]:
437        """Fetch a Destiny 2 player's memberships.
438
439        Parameters
440        -----------
441        name: `str`
442            The unique Bungie player name.
443        code : `int`
444            The unique Bungie display name code.
445        type: `aiobungie.internal.enums.MembershipType`
446            The player's membership type, e,g. XBOX, STEAM, PSN
447
448        Returns
449        --------
450        `collections.Sequence[aiobungie.crates.DestinyMembership]`
451            A sequence of the found Destiny 2 player memberships.
452            An empty sequence will be returned if no one found.
453
454        Raises
455        ------
456        `aiobungie.MembershipTypeError`
457            The provided membership type was invalid.
458        """
459        resp = await self.rest.fetch_player(name, code, type)
460
461        return self.factory.deserialize_destiny_memberships(resp)

Fetch a Destiny 2 player's memberships.

Parameters
  • name (str): The unique Bungie player name.
  • code (int): The unique Bungie display name code.
  • type (aiobungie.MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
Raises
async def fetch_character( self, member_id: int, membership_type: Union[int, aiobungie.MembershipType], character_id: int, components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.CharacterComponent:
463    async def fetch_character(
464        self,
465        member_id: int,
466        membership_type: typedefs.IntAnd[enums.MembershipType],
467        character_id: int,
468        components: list[enums.ComponentType],
469        auth: typing.Optional[str] = None,
470    ) -> components.CharacterComponent:
471        """Fetch a Destiny 2 character.
472
473        Parameters
474        ----------
475        member_id: `int`
476            A valid bungie member id.
477        character_id: `int`
478            The Destiny character id to retrieve.
479        membership_type: `aiobungie.internal.enums.MembershipType`
480            The member's membership type.
481        components: `list[aiobungie.ComponentType]`
482            Multiple arguments of character components to collect and return.
483
484        Other Parameters
485        ----------------
486        auth : `typing.Optional[str]`
487            A Bearer access_token to make the request with.
488            This is optional and limited to components that only requires an Authorization token.
489
490        Returns
491        -------
492        `aiobungie.crates.CharacterComponent`
493            A Bungie character component.
494
495        `aiobungie.MembershipTypeError`
496            The provided membership type was invalid.
497        """
498        resp = await self.rest.fetch_character(
499            member_id, membership_type, character_id, components, auth
500        )
501
502        return self.factory.deserialize_character_component(resp)

Fetch a Destiny 2 character.

Parameters
  • member_id (int): A valid bungie member id.
  • character_id (int): The Destiny character id to retrieve.
  • membership_type (aiobungie.MembershipType): The member's membership type.
  • components (list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> collections.abc.Sequence[aiobungie.crates.activity.ExtendedWeaponValues]:
504    async def fetch_unique_weapon_history(
505        self,
506        membership_id: int,
507        character_id: int,
508        membership_type: typedefs.IntAnd[enums.MembershipType],
509    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
510        """Fetch details about unique weapon usage for a character. Includes all exotics.
511
512        Parameters
513        ----------
514        membership_id : `int`
515            The Destiny user membership id.
516        character_id : `int`
517            The character id to retrieve.
518        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
519            The Destiny user's membership type.
520
521        Returns
522        -------
523        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
524            A sequence of the weapon's extended values.
525        """
526        resp = await self._rest.fetch_unique_weapon_history(
527            membership_id, character_id, membership_type
528        )
529
530        return [
531            self._factory.deserialize_extended_weapon_values(weapon)
532            for weapon in resp["weapons"]
533        ]

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, aiobungie.GameMode], *, membership_type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, page: int = 0, limit: int = 250) -> aiobungie.FlatIterator[aiobungie.crates.activity.Activity]:
537    async def fetch_activities(
538        self,
539        member_id: int,
540        character_id: int,
541        mode: typedefs.IntAnd[enums.GameMode],
542        *,
543        membership_type: typedefs.IntAnd[
544            enums.MembershipType
545        ] = enums.MembershipType.ALL,
546        page: int = 0,
547        limit: int = 250,
548    ) -> iterators.FlatIterator[activity.Activity]:
549        """Fetch a Destiny 2 activity for the specified character id.
550
551        Parameters
552        ----------
553        member_id: `int`
554            The user id that starts with `4611`.
555        character_id: `int`
556            The id of the character to retrieve the activities for.
557        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
558            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
559
560        Other Parameters
561        ----------------
562        membership_type: `aiobungie.internal.enums.MembershipType`
563            The Member ship type, if nothing was passed than it will return all.
564        page: int
565            The page number. Default is `0`
566        limit: int
567            Limit the returned result. Default is `250`.
568
569        Returns
570        -------
571        `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]`
572            An iterator of the player's activities.
573
574        Raises
575        ------
576        `aiobungie.MembershipTypeError`
577            The provided membership type was invalid.
578        """
579        resp = await self.rest.fetch_activities(
580            member_id,
581            character_id,
582            mode,
583            membership_type=membership_type,
584            page=page,
585            limit=limit,
586        )
587
588        return self.factory.deserialize_activities(resp)

Fetch a Destiny 2 activity for the specified character id.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve the activities for.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (aiobungie.MembershipType): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default is 0
  • limit (int): Limit the returned result. Default is 250.
Returns
Raises
async def fetch_post_activity(self, instance_id: int, /) -> aiobungie.crates.activity.PostActivity:
590    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
591        """Fetch a post activity details.
592
593        Parameters
594        ----------
595        instance_id: `int`
596            The activity instance id.
597
598        Returns
599        -------
600        `aiobungie.crates.PostActivity`
601           A post activity object.
602        """
603        resp = await self.rest.fetch_post_activity(instance_id)
604
605        return self.factory.deserialize_post_activity(resp)

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> aiobungie.FlatIterator[aiobungie.crates.activity.AggregatedActivity]:
607    async def fetch_aggregated_activity_stats(
608        self,
609        character_id: int,
610        membership_id: int,
611        membership_type: typedefs.IntAnd[enums.MembershipType],
612    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
613        """Fetch aggregated activity stats for a character.
614
615        Parameters
616        ----------
617        character_id: `int`
618            The id of the character to retrieve the activities for.
619        membership_id: `int`
620            The id of the user that started with `4611`.
621        membership_type: `aiobungie.internal.enums.MembershipType`
622            The Member ship type.
623
624        Returns
625        -------
626        `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]`
627            An iterator of the player's activities.
628
629        Raises
630        ------
631        `aiobungie.MembershipTypeError`
632            The provided membership type was invalid.
633        """
634        resp = await self.rest.fetch_aggregated_activity_stats(
635            character_id, membership_id, membership_type
636        )
637
638        return self.factory.deserialize_aggregated_activities(resp)

Fetch aggregated activity stats for a character.

Parameters
  • character_id (int): The id of the character to retrieve the activities for.
  • membership_id (int): The id of the user that started with 4611.
  • membership_type (aiobungie.MembershipType): The Member ship type.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> aiobungie.crates.clans.Clan:
642    async def fetch_clan_from_id(
643        self,
644        id: int,
645        /,
646        access_token: typing.Optional[str] = None,
647    ) -> clans.Clan:
648        """Fetch a Bungie Clan by its id.
649
650        Parameters
651        -----------
652        id: `int`
653            The clan id.
654
655        Returns
656        --------
657        `aiobungie.crates.Clan`
658            An Bungie clan.
659
660        Raises
661        ------
662        `aiobungie.NotFound`
663            The clan was not found.
664        """
665        resp = await self.rest.fetch_clan_from_id(id, access_token)
666
667        return self.factory.deserialize_clan(resp)

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> aiobungie.crates.clans.Clan:
669    async def fetch_clan(
670        self,
671        name: str,
672        /,
673        access_token: typing.Optional[str] = None,
674        *,
675        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
676    ) -> clans.Clan:
677        """Fetch a Clan by its name.
678        This method will return the first clan found with given name.
679
680        Parameters
681        ----------
682        name: `str`
683            The clan name
684
685        Other Parameters
686        ----------------
687        access_token : `typing.Optional[str]`
688            An optional access token to make the request with.
689
690            If the token was bound to a member of the clan,
691            This field `aiobungie.crates.Clan.current_user_membership` will be available
692            and will return the membership of the user who made this request.
693        type : `aiobungie.GroupType`
694            The group type, Default is aiobungie.GroupType.CLAN.
695
696        Returns
697        -------
698        `aiobungie.crates.Clan`
699            A Bungie clan.
700
701        Raises
702        ------
703        `aiobungie.NotFound`
704            The clan was not found.
705        """
706        resp = await self.rest.fetch_clan(name, access_token, type=type)
707
708        return self.factory.deserialize_clan(resp)

Fetch a Clan by its name. This method will return the first clan found with given name.

Parameters
  • name (str): The clan name
Other Parameters
Returns
Raises
async def fetch_clan_conversations( self, clan_id: int, /) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
710    async def fetch_clan_conversations(
711        self, clan_id: int, /
712    ) -> collections.Sequence[clans.ClanConversation]:
713        """Fetch the conversations/chat channels of the given clan id.
714
715        Parameters
716        ----------
717        clan_id : `int`
718            The clan id.
719
720        Returns
721        `collections.Sequence[aiobungie.crates.ClanConversation]`
722            A sequence of the clan chat channels.
723        """
724        resp = await self.rest.fetch_clan_conversations(clan_id)
725
726        return self.factory.deserialize_clan_conversations(resp)

Fetch the conversations/chat channels of the given clan id.

Parameters
async def fetch_clan_admins( self, clan_id: int, /) -> aiobungie.FlatIterator[aiobungie.crates.clans.ClanMember]:
728    async def fetch_clan_admins(
729        self, clan_id: int, /
730    ) -> iterators.FlatIterator[clans.ClanMember]:
731        """Fetch the clan founder and admins.
732
733        Parameters
734        ----------
735        clan_id : `int`
736            The clan id.
737
738        Returns
739        -------
740        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
741            An iterator over the found clan admins and founder.
742
743        Raises
744        ------
745        `aiobungie.NotFound`
746            The requested clan was not found.
747        """
748        resp = await self.rest.fetch_clan_admins(clan_id)
749
750        return self.factory.deserialize_clan_members(resp)

Fetch the clan founder and admins.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: aiobungie.GroupType = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
752    async def fetch_groups_for_member(
753        self,
754        member_id: int,
755        member_type: typedefs.IntAnd[enums.MembershipType],
756        /,
757        *,
758        filter: int = 0,
759        group_type: enums.GroupType = enums.GroupType.CLAN,
760    ) -> collections.Sequence[clans.GroupMember]:
761        """Fetch information about the groups that a given member has joined.
762
763        Parameters
764        ----------
765        member_id : `int`
766            The member's id
767        member_type : `aiobungie.MembershipType`
768            The member's membership type.
769
770        Other Parameters
771        ----------------
772        filter : `int`
773            Filter apply to list of joined groups. This Default to `0`
774        group_type : `aiobungie.GroupType`
775            The group's type.
776            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
777
778        Returns
779        -------
780        `collections.Sequence[aiobungie.crates.GroupMember]`
781            A sequence of joined groups for the fetched member.
782        """
783        resp = await self.rest.fetch_groups_for_member(
784            member_id, member_type, filter=filter, group_type=group_type
785        )
786
787        return [
788            self.factory.deserialize_group_member(group) for group in resp["results"]
789        ]

Fetch information about the groups that a given member has joined.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
791    async def fetch_potential_groups_for_member(
792        self,
793        member_id: int,
794        member_type: typedefs.IntAnd[enums.MembershipType],
795        /,
796        *,
797        filter: int = 0,
798        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
799    ) -> collections.Sequence[clans.GroupMember]:
800        """Fetch the potential groups for a clan member.
801
802        Parameters
803        ----------
804        member_id : `int`
805            The member's id
806        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
807            The member's membership type.
808
809        Other Parameters
810        ----------------
811        filter : `int`
812            Filter apply to list of joined groups. This Default to `0`
813        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
814            The group's type.
815            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
816
817        Returns
818        -------
819        `collections.Sequence[aiobungie.crates.GroupMember]`
820            A sequence of joined potential groups for the fetched member.
821        """
822        resp = await self.rest.fetch_potential_groups_for_member(
823            member_id, member_type, filter=filter, group_type=group_type
824        )
825
826        return [
827            self.factory.deserialize_group_member(group) for group in resp["results"]
828        ]

Fetch the potential groups for a clan member.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.FlatIterator[aiobungie.crates.clans.ClanMember]:
830    async def fetch_clan_members(
831        self,
832        clan_id: int,
833        /,
834        *,
835        name: typing.Optional[str] = None,
836        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
837    ) -> iterators.FlatIterator[clans.ClanMember]:
838        """Fetch Bungie clan members.
839
840        Parameters
841        ----------
842        clan_id : `int`
843            The clans id
844
845        Other Parameters
846        ----------------
847        name : `typing.Optional[str]`
848            If provided, Only players matching this name will be returned.
849        type : `aiobungie.MembershipType`
850            An optional clan member's membership type.
851            This parameter is used to filter the returned results
852            by the provided membership, For an example XBox memberships only,
853            Otherwise will return all memberships.
854
855        Returns
856        -------
857        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
858            An iterator over the bungie clan members.
859
860        Raises
861        ------
862        `aiobungie.NotFound`
863            The clan was not found.
864        """
865        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
866
867        return self.factory.deserialize_clan_members(resp)

Fetch Bungie clan members.

Parameters
  • clan_id (int): The clans id
Other Parameters
  • name (typing.Optional[str]): If provided, Only players matching this name will be returned.
  • type (aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
Raises
async def fetch_clan_banners(self) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
869    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
870        """Fetch the clan banners.
871
872        Returns
873        -------
874        `collections.Sequence[aiobungie.crates.ClanBanner]`
875            A sequence of the clan banners.
876        """
877        resp = await self.rest.fetch_clan_banners()
878
879        return self.factory.deserialize_clan_banners(resp)

Fetch the clan banners.

Returns
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> aiobungie.crates.clans.Clan:
882    async def kick_clan_member(
883        self,
884        access_token: str,
885        /,
886        group_id: int,
887        membership_id: int,
888        membership_type: typedefs.IntAnd[enums.MembershipType],
889    ) -> clans.Clan:
890        """Kick a member from the clan.
891
892        .. note::
893            This request requires OAuth2: oauth2: `AdminGroups` scope.
894
895        Parameters
896        ----------
897        access_token : `str`
898            The bearer access token associated with the bungie account.
899        group_id: `int`
900            The group id.
901        membership_id : `int`
902            The member id to kick.
903        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
904            The member's membership type.
905
906        Returns
907        -------
908        `aiobungie.crates.clan.Clan`
909            The clan that the member was kicked from.
910        """
911        resp = await self.rest.kick_clan_member(
912            access_token,
913            group_id=group_id,
914            membership_id=membership_id,
915            membership_type=membership_type,
916        )
917
918        return self.factory.deserialize_clan(resp)

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
  • aiobungie.crates.clan.Clan: The clan that the member was kicked from.
async def fetch_clan_weekly_rewards(self, clan_id: int) -> aiobungie.crates.milestones.Milestone:
920    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
921        """Fetch a Bungie clan's weekly reward state.
922
923        Parameters
924        ----------
925        clan_id : `int`
926            The clan's id.
927
928        Returns
929        -------
930        `aiobungie.crates.Milestone`
931            A runtime status of the clan's milestone data.
932        """
933
934        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
935
936        return self.factory.deserialize_milestone(resp)

Fetch a Bungie clan's weekly reward state.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_inventory_item(self, hash: int, /) -> aiobungie.crates.entity.InventoryEntity:
940    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
941        """Fetch a static inventory item entity given a its hash.
942
943        Parameters
944        ----------
945        hash: `int`
946            Inventory item's hash.
947
948        Returns
949        -------
950        `aiobungie.crates.InventoryEntity`
951            A bungie inventory item.
952        """
953        resp = await self.rest.fetch_inventory_item(hash)
954
955        return self.factory.deserialize_inventory_entity(resp)

Fetch a static inventory item entity given a its hash.

Parameters
  • hash (int): Inventory item's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> aiobungie.crates.entity.ObjectiveEntity:
957    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
958        """Fetch a Destiny objective entity given a its hash.
959
960        Parameters
961        ----------
962        hash: `int`
963            objective's hash.
964
965        Returns
966        -------
967        `aiobungie.crates.ObjectiveEntity`
968            An objective entity item.
969        """
970        resp = await self.rest.fetch_objective_entity(hash)
971
972        return self.factory.deserialize_objective_entity(resp)

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> aiobungie.FlatIterator[aiobungie.crates.entity.SearchableEntity]:
974    async def search_entities(
975        self, name: str, entity_type: str, *, page: int = 0
976    ) -> iterators.FlatIterator[entity.SearchableEntity]:
977        """Search for Destiny2 entities given a name and its type.
978
979        Parameters
980        ----------
981        name : `str`
982            The name of the entity, i.e., Thunderlord, One thousand voices.
983        entity_type : `str`
984            The type of the entity, AKA Definition,
985            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
986
987        Other Parameters
988        ----------------
989        page : `int`
990            An optional page to return. Default to 0.
991
992        Returns
993        -------
994        `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]`
995            An iterator over the found results matching the provided name.
996        """
997        resp = await self.rest.search_entities(name, entity_type, page=page)
998
999        return self.factory.deserialize_inventory_results(resp)

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition for emblems, weapons, and other inventory items.
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_fireteams( self, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[aiobungie.FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: int = 0, page: int = 0, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
1003    async def fetch_fireteams(
1004        self,
1005        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1006        *,
1007        platform: typedefs.IntAnd[
1008            fireteams.FireteamPlatform
1009        ] = fireteams.FireteamPlatform.ANY,
1010        language: typing.Union[
1011            fireteams.FireteamLanguage, str
1012        ] = fireteams.FireteamLanguage.ALL,
1013        date_range: int = 0,
1014        page: int = 0,
1015        slots_filter: int = 0,
1016    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1017        """Fetch public Bungie fireteams with open slots.
1018
1019        Parameters
1020        ----------
1021        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1022            The fireteam activity type.
1023
1024        Other Parameters
1025        ----------------
1026        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1027            If this is provided. Then the results will be filtered with the given platform.
1028            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1029        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1030            A locale language to filter the used language in that fireteam.
1031            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1032        date_range : `int`
1033            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1034        page : `int`
1035            The page number. By default its `0` which returns all available activities.
1036        slots_filter : `int`
1037            Filter the returned fireteams based on available slots. Default is `0`
1038
1039        Returns
1040        -------
1041        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1042            A sequence of `aiobungie.crates.Fireteam` or `None`.
1043        """
1044
1045        resp = await self.rest.fetch_fireteams(
1046            activity_type,
1047            platform=platform,
1048            language=language,
1049            date_range=date_range,
1050            page=page,
1051            slots_filter=slots_filter,
1052        )
1053
1054        return self.factory.deserialize_fireteams(resp)

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], date_range: int = 0, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
1056    async def fetch_avaliable_clan_fireteams(
1057        self,
1058        access_token: str,
1059        group_id: int,
1060        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1061        *,
1062        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1063        language: typing.Union[fireteams.FireteamLanguage, str],
1064        date_range: int = 0,
1065        page: int = 0,
1066        public_only: bool = False,
1067        slots_filter: int = 0,
1068    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1069        """Fetch a clan's fireteams with open slots.
1070
1071        .. note::
1072            This method requires OAuth2: ReadGroups scope.
1073
1074        Parameters
1075        ----------
1076        access_token : `str`
1077            The bearer access token associated with the bungie account.
1078        group_id : `int`
1079            The group/clan id of the fireteam.
1080        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1081            The fireteam activity type.
1082
1083        Other Parameters
1084        ----------------
1085        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1086            If this is provided. Then the results will be filtered with the given platform.
1087            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1088        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1089            A locale language to filter the used language in that fireteam.
1090            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1091        date_range : `int`
1092            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1093        page : `int`
1094            The page number. By default its `0` which returns all available activities.
1095        public_only: `bool`
1096            If set to True, Then only public fireteams will be returned.
1097        slots_filter : `int`
1098            Filter the returned fireteams based on available slots. Default is `0`
1099
1100        Returns
1101        -------
1102        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1103            A sequence of  fireteams found in the clan.
1104            `None` will be returned if nothing was found.
1105        """
1106        resp = await self.rest.fetch_avaliable_clan_fireteams(
1107            access_token,
1108            group_id,
1109            activity_type,
1110            platform=platform,
1111            language=language,
1112            date_range=date_range,
1113            page=page,
1114            public_only=public_only,
1115            slots_filter=slots_filter,
1116        )
1117
1118        return self.factory.deserialize_fireteams(resp)

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to 0.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
  • typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan. None will be returned if nothing was found.
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> aiobungie.crates.fireteams.AvailableFireteam:
1120    async def fetch_clan_fireteam(
1121        self, access_token: str, fireteam_id: int, group_id: int
1122    ) -> fireteams.AvailableFireteam:
1123        """Fetch a specific clan fireteam.
1124
1125        .. note::
1126            This method requires OAuth2: ReadGroups scope.
1127
1128        Parameters
1129        ----------
1130        access_token : `str`
1131            The bearer access token associated with the bungie account.
1132        group_id : `int`
1133            The group/clan id to fetch the fireteam from.
1134        fireteam_id : `int`
1135            The fireteam id to fetch.
1136
1137        Returns
1138        -------
1139        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1140            A sequence of available fireteams objects if exists. else `None` will be returned.
1141        """
1142        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1143
1144        return self.factory.deserialize_available_fireteams(
1145            resp, no_results=True
1146        )  # type: ignore[return-value]

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], filtered: bool = True, page: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]:
1148    async def fetch_my_clan_fireteams(
1149        self,
1150        access_token: str,
1151        group_id: int,
1152        *,
1153        include_closed: bool = True,
1154        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1155        language: typing.Union[fireteams.FireteamLanguage, str],
1156        filtered: bool = True,
1157        page: int = 0,
1158    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1159        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1160
1161        .. note::
1162            This method requires OAuth2: ReadGroups scope.
1163
1164        Parameters
1165        ----------
1166        access_token : str
1167            The bearer access token associated with the bungie account.
1168        group_id : int
1169            The group/clan id to fetch.
1170
1171        Other Parameters
1172        ----------------
1173        include_closed : bool
1174            If provided and set to True, It will also return closed fireteams.
1175            If provided and set to False, It will only return public fireteams. Default is True.
1176        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1177            If this is provided. Then the results will be filtered with the given platform.
1178            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1179        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1180            A locale language to filter the used language in that fireteam.
1181            Defaults to aiobungie.crates.FireteamLanguage.ALL
1182        filtered : bool
1183            If set to True, it will filter by clan. Otherwise not. Default is True.
1184        page : int
1185            The page number. By default its 0 which returns all available activities.
1186
1187        Returns
1188        -------
1189        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1190            A sequence of available fireteams objects if exists. else `None` will be returned.
1191        """
1192        resp = await self.rest.fetch_my_clan_fireteams(
1193            access_token,
1194            group_id,
1195            include_closed=include_closed,
1196            platform=platform,
1197            language=language,
1198            filtered=filtered,
1199            page=page,
1200        )
1201
1202        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]

A method that's similar to fetch_fireteams but requires OAuth2.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_friends( self, access_token: str, /) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
1206    async def fetch_friends(
1207        self, access_token: str, /
1208    ) -> collections.Sequence[friends.Friend]:
1209        """Fetch bungie friend list.
1210
1211        .. note::
1212            This requests OAuth2: ReadUserData scope.
1213
1214        Parameters
1215        -----------
1216        access_token : `str`
1217            The bearer access token associated with the bungie account.
1218
1219        Returns
1220        -------
1221        `collections.Sequence[aiobungie.crates.Friend]`
1222            A sequence of the friends associated with that access token.
1223        """
1224
1225        resp = await self.rest.fetch_friends(access_token)
1226
1227        return self.factory.deserialize_friends(resp)

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> aiobungie.crates.friends.FriendRequestView:
1229    async def fetch_friend_requests(
1230        self, access_token: str, /
1231    ) -> friends.FriendRequestView:
1232        """Fetch pending bungie friend requests queue.
1233
1234        .. note::
1235            This requests OAuth2: ReadUserData scope.
1236
1237        Parameters
1238        -----------
1239        access_token : `str`
1240            The bearer access token associated with the bungie account.
1241
1242        Returns
1243        -------
1244        `aiobungie.crates.FriendRequestView`
1245            A friend requests view of that associated access token.
1246        """
1247
1248        resp = await self.rest.fetch_friend_requests(access_token)
1249
1250        return self.factory.deserialize_friend_requests(resp)

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_application(self, appid: int, /) -> aiobungie.crates.application.Application:
1254    async def fetch_application(self, appid: int, /) -> application.Application:
1255        """Fetch a Bungie application.
1256
1257        Parameters
1258        -----------
1259        appid: `int`
1260            The application id.
1261
1262        Returns
1263        --------
1264        `aiobungie.crates.Application`
1265            A Bungie application.
1266        """
1267        resp = await self.rest.fetch_application(appid)
1268
1269        return self.factory.deserialize_app(resp)

Fetch a Bungie application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_public_milestone_content( self, milestone_hash: int, /) -> aiobungie.crates.milestones.MilestoneContent:
1273    async def fetch_public_milestone_content(
1274        self, milestone_hash: int, /
1275    ) -> milestones.MilestoneContent:
1276        """Fetch the milestone content given its hash.
1277
1278        Parameters
1279        ----------
1280        milestone_hash : `int`
1281            The milestone hash.
1282
1283        Returns
1284        -------
1285        `aiobungie.crates.milestones.MilestoneContent`
1286            A milestone content object.
1287        """
1288        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1289
1290        return self.factory.deserialize_public_milestone_content(resp)

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
  • aiobungie.crates.milestones.MilestoneContent: A milestone content object.
@typing.final
class ClosedReasons(aiobungie.Flag):
782@typing.final
783class ClosedReasons(Flag):
784    """A Flags enumeration representing the reasons why a person can't join this user's fireteam."""
785
786    NONE = 0
787    MATCHMAKING = 1
788    LOADING = 2
789    SOLO = 4
790    """The activity is required to be played solo."""
791    INTERNAL_REASONS = 8
792    """
793    The user can't be joined for one of a variety of internal reasons.
794    Basically, the game can't let you join at this time,
795    but for reasons that aren't under the control of this user
796    """
797    DISALLOWED_BY_GAME_STATE = 16
798    """The user's current activity/quest/other transitory game state is preventing joining."""
799    OFFLINE = 32768
800    """The user appears offline."""

A Flags enumeration representing the reasons why a person can't join this user's fireteam.

NONE = <ClosedReasons.NONE: 0>
MATCHMAKING = <ClosedReasons.MATCHMAKING: 1>
LOADING = <ClosedReasons.LOADING: 2>
SOLO = <ClosedReasons.SOLO: 4>

The activity is required to be played solo.

INTERNAL_REASONS = <ClosedReasons.INTERNAL_REASONS: 8>

The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user

DISALLOWED_BY_GAME_STATE = <ClosedReasons.DISALLOWED_BY_GAME_STATE: 16>

The user's current activity/quest/other transitory game state is preventing joining.

OFFLINE = <ClosedReasons.OFFLINE: 32768>

The user appears offline.

Inherited Members
Flag
name
value
@typing.final
class ComponentFields(aiobungie.Enum):
74@typing.final
75class ComponentFields(enums.Enum):
76    """An enum that provides fields found in a base component response."""
77
78    PRIVACY = ComponentPrivacy
79    DISABLED = False

An enum that provides fields found in a base component response.

PRIVACY = <ComponentFields.PRIVACY: <enum 'ComponentPrivacy'>>
DISABLED = <ComponentFields.DISABLED: False>
Inherited Members
Enum
name
value
@typing.final
class ComponentPrivacy(builtins.int, aiobungie.Enum):
65@typing.final
66class ComponentPrivacy(int, enums.Enum):
67    """An enum the provides privacy settings for profile components."""
68
69    NONE = 0
70    PUBLIC = 1
71    PRIVATE = 2

An enum the provides privacy settings for profile components.

NONE = <ComponentPrivacy.NONE: 0>
PUBLIC = <ComponentPrivacy.PUBLIC: 1>
PRIVATE = <ComponentPrivacy.PRIVATE: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ComponentType(aiobungie.Enum):
363@typing.final
364class ComponentType(Enum):
365    """An Enum for Destiny 2 profile Components."""
366
367    NONE = 0
368
369    PROFILE = 100
370    PROFILE_INVENTORIES = 102
371    PROFILE_CURRENCIES = 103
372    PROFILE_PROGRESSION = 104
373    ALL_PROFILES = (
374        PROFILE,
375        PROFILE_INVENTORIES,
376        PROFILE_CURRENCIES,
377        PROFILE_PROGRESSION,
378    )
379    """All profile components."""
380
381    VENDORS = 400
382    VENDOR_SALES = 402
383    VENDOR_RECEIPTS = 101
384    ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES)
385    """All vendor components."""
386
387    # Items
388    ITEM_INSTANCES = 300
389    ITEM_OBJECTIVES = 301
390    ITEM_PERKS = 302
391    ITEM_RENDER_DATA = 303
392    ITEM_STATS = 304
393    ITEM_SOCKETS = 305
394    ITEM_TALENT_GRINDS = 306
395    ITEM_PLUG_STATES = 308
396    ITEM_PLUG_OBJECTIVES = 309
397    ITEM_REUSABLE_PLUGS = 310
398
399    ALL_ITEMS = (
400        ITEM_PLUG_OBJECTIVES,
401        ITEM_PLUG_STATES,
402        ITEM_SOCKETS,
403        ITEM_INSTANCES,
404        ITEM_OBJECTIVES,
405        ITEM_PERKS,
406        ITEM_RENDER_DATA,
407        ITEM_STATS,
408        ITEM_TALENT_GRINDS,
409        ITEM_REUSABLE_PLUGS,
410    )
411    """All item components."""
412
413    PLATFORM_SILVER = 105
414    KIOSKS = 500
415    CURRENCY_LOOKUPS = 600
416    PRESENTATION_NODES = 700
417    COLLECTIBLES = 800
418    RECORDS = 900
419    TRANSITORY = 1000
420    METRICS = 1100
421    INVENTORIES = 102
422    STRING_VARIABLES = 1200
423    CRAFTABLES = 1300
424
425    CHARACTERS = 200
426    CHARACTER_INVENTORY = 201
427    CHARECTER_PROGRESSION = 202
428    CHARACTER_RENDER_DATA = 203
429    CHARACTER_ACTIVITIES = 204
430    CHARACTER_EQUIPMENT = 205
431
432    ALL_CHARACTERS = (
433        CHARACTERS,
434        CHARACTER_INVENTORY,
435        CHARECTER_PROGRESSION,
436        CHARACTER_RENDER_DATA,
437        CHARACTER_ACTIVITIES,
438        CHARACTER_EQUIPMENT,
439        RECORDS,
440    )
441    """All character components."""
442
443    ALL = (
444        *ALL_PROFILES,  # type: ignore
445        *ALL_CHARACTERS,  # type: ignore
446        *ALL_VENDORS,  # type: ignore
447        *ALL_ITEMS,  # type: ignore
448        RECORDS,
449        CURRENCY_LOOKUPS,
450        PRESENTATION_NODES,
451        COLLECTIBLES,
452        KIOSKS,
453        METRICS,
454        PLATFORM_SILVER,
455        INVENTORIES,
456        STRING_VARIABLES,
457        TRANSITORY,
458        CRAFTABLES,
459    )
460    """ALl components included."""

An Enum for Destiny 2 profile Components.

NONE = <ComponentType.NONE: 0>
PROFILE = <ComponentType.PROFILE: 100>
PROFILE_INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
PROFILE_CURRENCIES = <ComponentType.PROFILE_CURRENCIES: 103>
PROFILE_PROGRESSION = <ComponentType.PROFILE_PROGRESSION: 104>
ALL_PROFILES = <ComponentType.ALL_PROFILES: (100, 102, 103, 104)>

All profile components.

VENDORS = <ComponentType.VENDORS: 400>
VENDOR_SALES = <ComponentType.VENDOR_SALES: 402>
VENDOR_RECEIPTS = <ComponentType.VENDOR_RECEIPTS: 101>
ALL_VENDORS = <ComponentType.ALL_VENDORS: (400, 101, 402)>

All vendor components.

ITEM_INSTANCES = <ComponentType.ITEM_INSTANCES: 300>
ITEM_OBJECTIVES = <ComponentType.ITEM_OBJECTIVES: 301>
ITEM_PERKS = <ComponentType.ITEM_PERKS: 302>
ITEM_RENDER_DATA = <ComponentType.ITEM_RENDER_DATA: 303>
ITEM_STATS = <ComponentType.ITEM_STATS: 304>
ITEM_SOCKETS = <ComponentType.ITEM_SOCKETS: 305>
ITEM_TALENT_GRINDS = <ComponentType.ITEM_TALENT_GRINDS: 306>
ITEM_PLUG_STATES = <ComponentType.ITEM_PLUG_STATES: 308>
ITEM_PLUG_OBJECTIVES = <ComponentType.ITEM_PLUG_OBJECTIVES: 309>
ITEM_REUSABLE_PLUGS = <ComponentType.ITEM_REUSABLE_PLUGS: 310>
ALL_ITEMS = <ComponentType.ALL_ITEMS: (309, 308, 305, 300, 301, 302, 303, 304, 306, 310)>

All item components.

PLATFORM_SILVER = <ComponentType.PLATFORM_SILVER: 105>
KIOSKS = <ComponentType.KIOSKS: 500>
CURRENCY_LOOKUPS = <ComponentType.CURRENCY_LOOKUPS: 600>
PRESENTATION_NODES = <ComponentType.PRESENTATION_NODES: 700>
COLLECTIBLES = <ComponentType.COLLECTIBLES: 800>
RECORDS = <ComponentType.RECORDS: 900>
TRANSITORY = <ComponentType.TRANSITORY: 1000>
METRICS = <ComponentType.METRICS: 1100>
INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
STRING_VARIABLES = <ComponentType.STRING_VARIABLES: 1200>
CRAFTABLES = <ComponentType.CRAFTABLES: 1300>
CHARACTERS = <ComponentType.CHARACTERS: 200>
CHARACTER_INVENTORY = <ComponentType.CHARACTER_INVENTORY: 201>
CHARECTER_PROGRESSION = <ComponentType.CHARECTER_PROGRESSION: 202>
CHARACTER_RENDER_DATA = <ComponentType.CHARACTER_RENDER_DATA: 203>
CHARACTER_ACTIVITIES = <ComponentType.CHARACTER_ACTIVITIES: 204>
CHARACTER_EQUIPMENT = <ComponentType.CHARACTER_EQUIPMENT: 205>
ALL_CHARACTERS = <ComponentType.ALL_CHARACTERS: (200, 201, 202, 203, 204, 205, 900)>

All character components.

ALL = <ComponentType.ALL: (100, 102, 103, 104, 200, 201, 202, 203, 204, 205, 900, 400, 101, 402, 309, 308, 305, 300, 301, 302, 303, 304, 306, 310, 900, 600, 700, 800, 500, 1100, 105, 102, 1200, 1000, 1300)>

ALl components included.

Inherited Members
Enum
name
value
@typing.final
class CredentialType(builtins.int, aiobungie.Enum):
664@typing.final
665class CredentialType(int, Enum):
666    """The types of the accounts system supports at bungie."""
667
668    NONE = 0
669    XUID = 1
670    PSNID = 2
671    WILD = 3
672    FAKE = 4
673    FACEBOOK = 5
674    GOOGLE = 8
675    WINDOWS = 9
676    DEMONID = 10
677    STEAMID = 12
678    BATTLENETID = 14
679    STADIAID = 16
680    TWITCHID = 18

The types of the accounts system supports at bungie.

NONE = <CredentialType.NONE: 0>
XUID = <CredentialType.XUID: 1>
PSNID = <CredentialType.PSNID: 2>
WILD = <CredentialType.WILD: 3>
FAKE = <CredentialType.FAKE: 4>
FACEBOOK = <CredentialType.FACEBOOK: 5>
GOOGLE = <CredentialType.GOOGLE: 8>
WINDOWS = <CredentialType.WINDOWS: 9>
DEMONID = <CredentialType.DEMONID: 10>
STEAMID = <CredentialType.STEAMID: 12>
BATTLENETID = <CredentialType.BATTLENETID: 14>
STADIAID = <CredentialType.STADIAID: 16>
TWITCHID = <CredentialType.TWITCHID: 18>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class DamageType(builtins.int, aiobungie.Enum):
542@typing.final
543class DamageType(int, Enum):
544    """Enums for Destiny Damage types"""
545
546    NONE = 0
547    KINETIC = 1
548    ARC = 2
549    SOLAR = 3
550    VOID = 4
551    RAID = 5
552    """This is a special damage type reserved for some raid activity encounters."""
553    STASIS = 6

Enums for Destiny Damage types

NONE = <DamageType.NONE: 0>
KINETIC = <DamageType.KINETIC: 1>
ARC = <DamageType.ARC: 2>
SOLAR = <DamageType.SOLAR: 3>
VOID = <DamageType.VOID: 4>
RAID = <DamageType.RAID: 5>

This is a special damage type reserved for some raid activity encounters.

STASIS = <DamageType.STASIS: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Difficulty(builtins.int, aiobungie.Enum):
65@typing.final
66class Difficulty(int, enums.Enum):
67    """An enum for activities difficulties."""
68
69    TRIVIAL = 0
70    EASY = 1
71    NORMAL = 2
72    CHALLENGING = 3
73    HARD = 4
74    BRAVE = 5
75    ALMOST_IMPOSSIBLE = 6
76    IMPOSSIBLE = 7

An enum for activities difficulties.

TRIVIAL = <Difficulty.TRIVIAL: 0>
EASY = <Difficulty.EASY: 1>
NORMAL = <Difficulty.NORMAL: 2>
CHALLENGING = <Difficulty.CHALLENGING: 3>
HARD = <Difficulty.HARD: 4>
BRAVE = <Difficulty.BRAVE: 5>
ALMOST_IMPOSSIBLE = <Difficulty.ALMOST_IMPOSSIBLE: 6>
IMPOSSIBLE = <Difficulty.IMPOSSIBLE: 7>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Dungeon(builtins.int, aiobungie.Enum):
165@typing.final
166class Dungeon(int, Enum):
167    """An Enum for all available Dungeon/Like missions in Destiny 2."""
168
169    NORMAL_PRESAGE = 2124066889
170    """Normal Presage"""
171
172    MASTER_PRESAGE = 4212753278
173    """Master Presage"""
174
175    HARBINGER = 1738383283
176    """Harbinger"""
177
178    PROPHECY = 4148187374
179    """Prophecy"""
180
181    MASTER_POH = 785700673
182    """Master Pit of Heresy?"""
183
184    LEGEND_POH = 785700678
185    """Legend Pit of Heresy?"""
186
187    POH = 1375089621
188    """Normal Pit of Heresy."""
189
190    SHATTERED = 2032534090
191    """Shattered Throne"""
192
193    GOA_LEGEND = 4078656646
194    """Grasp of Avarice legend."""
195
196    GOA_MASTER = 3774021532
197    """Grasp of Avarice master."""

An Enum for all available Dungeon/Like missions in Destiny 2.

NORMAL_PRESAGE = <Dungeon.NORMAL_PRESAGE: 2124066889>

Normal Presage

MASTER_PRESAGE = <Dungeon.MASTER_PRESAGE: 4212753278>

Master Presage

HARBINGER = <Dungeon.HARBINGER: 1738383283>

Harbinger

PROPHECY = <Dungeon.PROPHECY: 4148187374>

Prophecy

MASTER_POH = <Dungeon.MASTER_POH: 785700673>

Master Pit of Heresy?

LEGEND_POH = <Dungeon.LEGEND_POH: 785700678>

Legend Pit of Heresy?

POH = <Dungeon.POH: 1375089621>

Normal Pit of Heresy.

SHATTERED = <Dungeon.SHATTERED: 2032534090>

Shattered Throne

GOA_LEGEND = <Dungeon.GOA_LEGEND: 4078656646>

Grasp of Avarice legend.

GOA_MASTER = <Dungeon.GOA_MASTER: 3774021532>

Grasp of Avarice master.

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Enum(enum.Enum):
77class Enum(__enum.Enum):
78    """Builtin Python enum with extra handlings."""
79
80    @property
81    def name(self) -> str:  # type: ignore[override]
82        return self._name_
83
84    @property
85    def value(self) -> typing.Any:  # type: ignore[override]
86        return self._value_
87
88    def __str__(self) -> str:
89        return self._name_
90
91    def __repr__(self) -> str:
92        return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>"
93
94    def __int__(self) -> int:
95        if isinstance(self.value, _ITERABLE):
96            raise TypeError(
97                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
98            )
99        return int(self.value)

Builtin Python enum with extra handlings.

name: str
value: Any
class Factory(aiobungie.interfaces.factory.FactoryInterface):
  61class Factory(interfaces.FactoryInterface):
  62    """The base deserialization factory class for all aiobungie objects.
  63
  64    Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
  65    into a `aiobungie.crates` Python classes.
  66    """
  67
  68    __slots__ = ("_net",)
  69
  70    def __init__(self, net: traits.Netrunner) -> None:
  71        self._net = net
  72
  73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
  74        return user.BungieUser(
  75            id=int(data["membershipId"]),
  76            created_at=time.clean_date(data["firstAccess"]),
  77            name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined),
  78            is_deleted=data["isDeleted"],
  79            about=data["about"],
  80            updated_at=time.clean_date(data["lastUpdate"]),
  81            psn_name=data.get("psnDisplayName", None),
  82            stadia_name=data.get("stadiaDisplayName", None),
  83            steam_name=data.get("steamDisplayName", None),
  84            twitch_name=data.get("twitchDisplayName", None),
  85            blizzard_name=data.get("blizzardDisplayName", None),
  86            status=data["statusText"],
  87            locale=data["locale"],
  88            picture=assets.Image(path=str(data["profilePicturePath"])),
  89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
  90            unique_name=data.get("uniqueName", None),
  91            theme_id=int(data["profileTheme"]),
  92            show_activity=bool(data["showActivity"]),
  93            theme_name=data["profileThemeName"],
  94            display_title=data["userTitleDisplay"],
  95        )
  96
  97    def deserialize_partial_bungie_user(
  98        self, payload: typedefs.JSONObject
  99    ) -> user.PartialBungieUser:
 100        return user.PartialBungieUser(
 101            net=self._net,
 102            types=[
 103                enums.MembershipType(type_)
 104                for type_ in payload.get("applicableMembershipTypes", [])
 105            ],
 106            name=payload.get("displayName", undefined.Undefined),
 107            id=int(payload["membershipId"]),
 108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 109            is_public=payload["isPublic"],
 110            icon=assets.Image(payload.get("iconPath", "")),
 111            type=enums.MembershipType(payload["membershipType"]),
 112        )
 113
 114    def deserialize_destiny_membership(
 115        self, payload: typedefs.JSONObject
 116    ) -> user.DestinyMembership:
 117        name: undefined.UndefinedOr[str] = undefined.Undefined
 118        if (
 119            raw_name := payload.get("bungieGlobalDisplayName", "")
 120        ) and not typedefs.is_unknown(raw_name):
 121            name = raw_name
 122
 123        return user.DestinyMembership(
 124            net=self._net,
 125            id=int(payload["membershipId"]),
 126            name=name,
 127            code=payload.get("bungieGlobalDisplayNameCode", None),
 128            last_seen_name=payload.get("LastSeenDisplayName")
 129            or payload.get("displayName")  # noqa: W503
 130            or "",  # noqa: W503
 131            type=enums.MembershipType(payload["membershipType"]),
 132            is_public=payload["isPublic"],
 133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 134            icon=assets.Image(payload.get("iconPath", "")),
 135            types=[
 136                enums.MembershipType(type_)
 137                for type_ in payload.get("applicableMembershipTypes", [])
 138            ],
 139        )
 140
 141    def deserialize_destiny_memberships(
 142        self, data: typedefs.JSONArray
 143    ) -> collections.Sequence[user.DestinyMembership]:
 144        return [self.deserialize_destiny_membership(membership) for membership in data]
 145
 146    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
 147
 148        primary_membership_id: typing.Optional[int] = None
 149        if raw_primary_id := data.get("primaryMembershipId"):
 150            primary_membership_id = int(raw_primary_id)
 151
 152        return user.User(
 153            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
 154            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
 155            primary_membership_id=primary_membership_id,
 156        )
 157
 158    def deserialize_searched_user(
 159        self, payload: typedefs.JSONObject
 160    ) -> user.SearchableDestinyUser:
 161        name: undefined.UndefinedOr[str] = undefined.Undefined
 162        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
 163            raw_name
 164        ):
 165            name = raw_name
 166
 167        code: typing.Optional[int] = None
 168        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
 169            code = int(raw_code)
 170
 171        bungie_id: typing.Optional[int] = None
 172        if raw_bungie_id := payload.get("bungieNetMembershipId"):
 173            bungie_id = int(raw_bungie_id)
 174
 175        return user.SearchableDestinyUser(
 176            name=name,
 177            code=code,
 178            bungie_id=bungie_id,
 179            memberships=self.deserialize_destiny_memberships(
 180                payload["destinyMemberships"]
 181            ),
 182        )
 183
 184    def deserialize_user_credentials(
 185        self, payload: typedefs.JSONArray
 186    ) -> collections.Sequence[user.UserCredentials]:
 187        return [
 188            user.UserCredentials(
 189                type=enums.CredentialType(int(creds["credentialType"])),
 190                display_name=creds["credentialDisplayName"],
 191                is_public=creds["isPublic"],
 192                self_as_string=creds.get("credentialAsString", undefined.Undefined),
 193            )
 194            for creds in payload
 195        ]
 196
 197    @staticmethod
 198    def set_themese_attrs(
 199        payload: typedefs.JSONArray, /
 200    ) -> typing.Collection[user.UserThemes]:
 201        return [
 202            user.UserThemes(
 203                id=int(entry["userThemeId"]),
 204                name=entry["userThemeName"]
 205                if "userThemeName" in entry
 206                else undefined.Undefined,
 207                description=entry["userThemeDescription"]
 208                if "userThemeDescription" in entry
 209                else undefined.Undefined,
 210            )
 211            for entry in payload
 212        ]
 213
 214    def deserialize_user_themes(
 215        self, payload: typedefs.JSONArray
 216    ) -> collections.Sequence[user.UserThemes]:
 217        return list(self.set_themese_attrs(payload))
 218
 219    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
 220
 221        # This is kinda redundant
 222        data = payload
 223
 224        # This is always outside the details.
 225        current_user_map: typing.Optional[
 226            collections.Mapping[str, clans.ClanMember]
 227        ] = None
 228        if raw_current_user_map := payload.get("currentUserMemberMap"):
 229            current_user_map = {
 230                membership_type: self.deserialize_clan_member(membership)
 231                for membership_type, membership in raw_current_user_map.items()
 232            }
 233
 234        try:
 235            data = payload["detail"]
 236        except KeyError:
 237            pass
 238
 239        id = data["groupId"]
 240        name = data["name"]
 241        created_at = data["creationDate"]
 242        member_count = data["memberCount"]
 243        about = data["about"]
 244        motto = data["motto"]
 245        is_public = data["isPublic"]
 246        banner = assets.Image(str(data["bannerPath"]))
 247        avatar = assets.Image(str(data["avatarPath"]))
 248        tags = data["tags"]
 249        type = data["groupType"]
 250
 251        features = data["features"]
 252        features_obj = clans.ClanFeatures(
 253            max_members=features["maximumMembers"],
 254            max_membership_types=features["maximumMembershipsOfGroupType"],
 255            capabilities=features["capabilities"],
 256            membership_types=features["membershipTypes"],
 257            invite_permissions=features["invitePermissionOverride"],
 258            update_banner_permissions=features["updateBannerPermissionOverride"],
 259            update_culture_permissions=features["updateCulturePermissionOverride"],
 260            join_level=features["joinLevel"],
 261        )
 262
 263        information: typedefs.JSONObject = data["clanInfo"]
 264        progression: collections.Mapping[int, progressions.Progression] = {
 265            int(prog_hash): self.deserialize_progressions(prog)
 266            for prog_hash, prog in information["d2ClanProgressions"].items()
 267        }
 268
 269        founder: typedefs.NoneOr[clans.ClanMember] = None
 270        if raw_founder := payload.get("founder"):
 271            founder = self.deserialize_clan_member(raw_founder)
 272
 273        return clans.Clan(
 274            net=self._net,
 275            id=int(id),
 276            name=name,
 277            type=enums.GroupType(type),
 278            created_at=time.clean_date(created_at),
 279            member_count=member_count,
 280            motto=motto,
 281            about=about,
 282            is_public=is_public,
 283            banner=banner,
 284            avatar=avatar,
 285            tags=tags,
 286            features=features_obj,
 287            owner=founder,
 288            progressions=progression,
 289            call_sign=information["clanCallsign"],
 290            banner_data=information["clanBannerData"],
 291            chat_security=data["chatSecurity"],
 292            conversation_id=int(data["conversationId"]),
 293            allow_chat=data["allowChat"],
 294            theme=data["theme"],
 295            current_user_membership=current_user_map,
 296        )
 297
 298    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
 299        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
 300        return clans.ClanMember(
 301            net=self._net,
 302            last_seen_name=destiny_user.last_seen_name,
 303            id=destiny_user.id,
 304            name=destiny_user.name,
 305            icon=destiny_user.icon,
 306            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
 307            group_id=int(data["groupId"]),
 308            joined_at=time.clean_date(data["joinDate"]),
 309            types=destiny_user.types,
 310            is_public=destiny_user.is_public,
 311            type=destiny_user.type,
 312            code=destiny_user.code,
 313            is_online=data["isOnline"],
 314            crossave_override=destiny_user.crossave_override,
 315            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
 316            if "bungieNetUserInfo" in data
 317            else None,
 318            member_type=enums.ClanMemberType(int(data["memberType"])),
 319        )
 320
 321    def deserialize_clan_members(
 322        self, data: typedefs.JSONObject, /
 323    ) -> iterators.FlatIterator[clans.ClanMember]:
 324        return iterators.FlatIterator(
 325            [self.deserialize_clan_member(member) for member in data["results"]]
 326        )
 327
 328    def deserialize_group_member(
 329        self, payload: typedefs.JSONObject
 330    ) -> clans.GroupMember:
 331        member = payload["member"]
 332        return clans.GroupMember(
 333            net=self._net,
 334            join_date=time.clean_date(member["joinDate"]),
 335            group_id=int(member["groupId"]),
 336            member_type=enums.ClanMemberType(member["memberType"]),
 337            is_online=member["isOnline"],
 338            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
 339            inactive_memberships=payload.get("areAllMembershipsInactive", None),
 340            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
 341            group=self.deserialize_clan(payload["group"]),
 342        )
 343
 344    def _deserialize_clan_conversation(
 345        self, payload: typedefs.JSONObject
 346    ) -> clans.ClanConversation:
 347        return clans.ClanConversation(
 348            net=self._net,
 349            id=int(payload["conversationId"]),
 350            group_id=int(payload["groupId"]),
 351            name=(
 352                payload["chatName"]
 353                if not typedefs.is_unknown(payload["chatName"])
 354                else undefined.Undefined
 355            ),
 356            chat_enabled=payload["chatEnabled"],
 357            security=payload["chatSecurity"],
 358        )
 359
 360    def deserialize_clan_conversations(
 361        self, payload: typedefs.JSONArray
 362    ) -> collections.Sequence[clans.ClanConversation]:
 363        return [self._deserialize_clan_conversation(conv) for conv in payload]
 364
 365    def deserialize_app_owner(
 366        self, payload: typedefs.JSONObject
 367    ) -> application.ApplicationOwner:
 368        return application.ApplicationOwner(
 369            net=self._net,
 370            name=payload.get("bungieGlobalDisplayName", undefined.Undefined),
 371            id=int(payload["membershipId"]),
 372            type=enums.MembershipType(payload["membershipType"]),
 373            icon=assets.Image(str(payload["iconPath"])),
 374            is_public=payload["isPublic"],
 375            code=payload.get("bungieGlobalDisplayNameCode", None),
 376        )
 377
 378    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
 379        return application.Application(
 380            id=int(payload["applicationId"]),
 381            name=payload["name"],
 382            link=payload["link"],
 383            status=payload["status"],
 384            redirect_url=payload.get("redirectUrl", None),
 385            created_at=time.clean_date(str(payload["creationDate"])),
 386            published_at=time.clean_date(str(payload["firstPublished"])),
 387            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
 388            scope=payload.get("scope", undefined.Undefined),
 389        )
 390
 391    def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character:
 392        total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True)
 393        return character.Character(
 394            net=self._net,
 395            id=int(payload["characterId"]),
 396            gender=enums.Gender(payload["genderType"]),
 397            race=enums.Race(payload["raceType"]),
 398            class_type=enums.Class(payload["classType"]),
 399            emblem=assets.Image(str(payload["emblemBackgroundPath"])),
 400            emblem_icon=assets.Image(str(payload["emblemPath"])),
 401            emblem_hash=int(payload["emblemHash"]),
 402            last_played=time.clean_date(payload["dateLastPlayed"]),
 403            total_played_time=total_time,
 404            member_id=int(payload["membershipId"]),
 405            member_type=enums.MembershipType(payload["membershipType"]),
 406            level=payload["baseCharacterLevel"],
 407            title_hash=payload.get("titleRecordHash", None),
 408            light=payload["light"],
 409            stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()},
 410        )
 411
 412    def deserialize_profile(
 413        self, payload: typedefs.JSONObject, /
 414    ) -> typing.Optional[profile.Profile]:
 415        if (raw_profile := payload.get("data")) is None:
 416            return None
 417
 418        payload = raw_profile
 419        id = int(payload["userInfo"]["membershipId"])
 420        name = payload["userInfo"]["displayName"]
 421        is_public = payload["userInfo"]["isPublic"]
 422        type = enums.MembershipType(payload["userInfo"]["membershipType"])
 423        last_played = time.clean_date(str(payload["dateLastPlayed"]))
 424        character_ids = [int(cid) for cid in payload["characterIds"]]
 425        power_cap = payload["currentSeasonRewardPowerCap"]
 426
 427        return profile.Profile(
 428            id=int(id),
 429            name=name,
 430            is_public=is_public,
 431            type=type,
 432            last_played=last_played,
 433            character_ids=character_ids,
 434            power_cap=power_cap,
 435            net=self._net,
 436        )
 437
 438    def deserialize_profile_item(
 439        self, payload: typedefs.JSONObject
 440    ) -> profile.ProfileItemImpl:
 441
 442        instance_id: typing.Optional[int] = None
 443        if raw_instance_id := payload.get("itemInstanceId"):
 444            instance_id = int(raw_instance_id)
 445
 446        version_number: typing.Optional[int] = None
 447        if raw_version := payload.get("versionNumber"):
 448            version_number = int(raw_version)
 449
 450        transfer_status = enums.TransferStatus(payload["transferStatus"])
 451
 452        return profile.ProfileItemImpl(
 453            net=self._net,
 454            hash=payload["itemHash"],
 455            quantity=payload["quantity"],
 456            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
 457            location=enums.ItemLocation(payload["location"]),
 458            bucket=payload["bucketHash"],
 459            transfer_status=transfer_status,
 460            lockable=payload["lockable"],
 461            state=enums.ItemState(payload["state"]),
 462            dismantel_permissions=payload["dismantlePermission"],
 463            is_wrapper=payload["isWrapper"],
 464            instance_id=instance_id,
 465            version_number=version_number,
 466            ornament_id=payload.get("overrideStyleItemHash"),
 467        )
 468
 469    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
 470        return records.Objective(
 471            net=self._net,
 472            hash=payload["objectiveHash"],
 473            visible=payload["visible"],
 474            complete=payload["complete"],
 475            completion_value=payload["completionValue"],
 476            progress=payload.get("progress"),
 477            destination_hash=payload.get("destinationHash"),
 478            activity_hash=payload.get("activityHash"),
 479        )
 480
 481    def deserialize_records(
 482        self,
 483        payload: typedefs.JSONObject,
 484        scores: typing.Optional[records.RecordScores] = None,
 485        **nodes: int,
 486    ) -> records.Record:
 487        objectives: typing.Optional[list[records.Objective]] = None
 488        interval_objectives: typing.Optional[list[records.Objective]] = None
 489        record_state: typedefs.IntAnd[records.RecordState]
 490
 491        record_state = records.RecordState(payload["state"])
 492
 493        if raw_objs := payload.get("objectives"):
 494            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
 495
 496        if raw_interval_objs := payload.get("intervalObjectives"):
 497            interval_objectives = [
 498                self.deserialize_objectives(obj) for obj in raw_interval_objs
 499            ]
 500
 501        return records.Record(
 502            scores=scores,
 503            categories_node_hash=nodes.get("categories_hash", undefined.Undefined),
 504            seals_node_hash=nodes.get("seals_hash", undefined.Undefined),
 505            state=record_state,
 506            objectives=objectives,
 507            interval_objectives=interval_objectives,
 508            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 509            completion_times=payload.get("completedCount", None),
 510            reward_visibility=payload.get("rewardVisibilty", None),
 511        )
 512
 513    def deserialize_character_records(
 514        self,
 515        payload: typedefs.JSONObject,
 516        scores: typing.Optional[records.RecordScores] = None,
 517        record_hashes: typing.Optional[list[int]] = None,
 518    ) -> records.CharacterRecord:
 519
 520        record = self.deserialize_records(payload, scores)
 521        return records.CharacterRecord(
 522            scores=scores,
 523            categories_node_hash=record.categories_node_hash,
 524            seals_node_hash=record.seals_node_hash,
 525            state=record.state,
 526            objectives=record.objectives,
 527            interval_objectives=record.interval_objectives,
 528            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 529            completion_times=payload.get("completedCount"),
 530            reward_visibility=payload.get("rewardVisibilty"),
 531            record_hashes=record_hashes or [],
 532        )
 533
 534    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
 535        return character.Dye(
 536            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
 537        )
 538
 539    def deserialize_character_customization(
 540        self, payload: typedefs.JSONObject
 541    ) -> character.CustomizationOptions:
 542        return character.CustomizationOptions(
 543            personality=payload["personality"],
 544            face=payload["face"],
 545            skin_color=payload["skinColor"],
 546            lip_color=payload["lipColor"],
 547            eye_color=payload["eyeColor"],
 548            hair_colors=payload.get("hairColors", []),
 549            feature_colors=payload.get("featureColors", []),
 550            decal_color=payload["decalColor"],
 551            wear_helmet=payload["wearHelmet"],
 552            hair_index=payload["hairIndex"],
 553            feature_index=payload["featureIndex"],
 554            decal_index=payload["decalIndex"],
 555        )
 556
 557    def deserialize_character_minimal_equipments(
 558        self, payload: typedefs.JSONObject
 559    ) -> character.MinimalEquipments:
 560        dyes = None
 561        if raw_dyes := payload.get("dyes"):
 562            if raw_dyes:
 563                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
 564        return character.MinimalEquipments(
 565            net=self._net, item_hash=payload["itemHash"], dyes=dyes
 566        )
 567
 568    def deserialize_character_render_data(
 569        self, payload: typedefs.JSONObject, /
 570    ) -> character.RenderedData:
 571        return character.RenderedData(
 572            net=self._net,
 573            customization=self.deserialize_character_customization(
 574                payload["customization"]
 575            ),
 576            custom_dyes=[
 577                self.deserialize_character_dye(dye)
 578                for dye in payload["customDyes"]
 579                if dye
 580            ],
 581            equipment=[
 582                self.deserialize_character_minimal_equipments(equipment)
 583                for equipment in payload["peerView"]["equipment"]
 584            ],
 585        )
 586
 587    def deserialize_available_activity(
 588        self, payload: typedefs.JSONObject
 589    ) -> activity.AvailableActivity:
 590        return activity.AvailableActivity(
 591            hash=payload["activityHash"],
 592            is_new=payload["isNew"],
 593            is_completed=payload["isCompleted"],
 594            is_visible=payload["isVisible"],
 595            display_level=payload.get("displayLevel"),
 596            recommended_light=payload.get("recommendedLight"),
 597            difficulty=activity.Difficulty(payload["difficultyTier"]),
 598            can_join=payload["canJoin"],
 599            can_lead=payload["canLead"],
 600        )
 601
 602    def deserialize_character_activity(
 603        self, payload: typedefs.JSONObject
 604    ) -> activity.CharacterActivity:
 605        current_mode: typing.Optional[enums.GameMode] = None
 606        if raw_current_mode := payload.get("currentActivityModeType"):
 607            current_mode = enums.GameMode(raw_current_mode)
 608
 609        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
 610        if raw_current_modes := payload.get("currentActivityModeTypes"):
 611            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
 612
 613        return activity.CharacterActivity(
 614            date_started=time.clean_date(payload["dateActivityStarted"]),
 615            current_hash=payload["currentActivityHash"],
 616            current_mode_hash=payload["currentActivityModeHash"],
 617            current_mode=current_mode,
 618            current_mode_hashes=payload.get("currentActivityModeHashes"),
 619            current_mode_types=current_mode_types,
 620            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
 621            last_story_hash=payload["lastCompletedStoryHash"],
 622            available_activities=[
 623                self.deserialize_available_activity(activity_)
 624                for activity_ in payload["availableActivities"]
 625            ],
 626        )
 627
 628    def deserialize_profile_items(
 629        self, payload: typedefs.JSONObject, /
 630    ) -> list[profile.ProfileItemImpl]:
 631        return [self.deserialize_profile_item(item) for item in payload["items"]]
 632
 633    def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node:
 634        return records.Node(
 635            state=int(payload["state"]),
 636            objective=self.deserialize_objectives(payload["objective"])
 637            if "objective" in payload
 638            else None,
 639            progress_value=int(payload["progressValue"]),
 640            completion_value=int(payload["completionValue"]),
 641            record_category_score=int(payload["recordCategoryScore"])
 642            if "recordCategoryScore" in payload
 643            else None,
 644        )
 645
 646    @staticmethod
 647    def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible:
 648        recent_collectibles: typing.Optional[collections.Collection[int]] = None
 649        if raw_recent_collectibles := payload.get("recentCollectibleHashes"):
 650            recent_collectibles = [
 651                int(item_hash) for item_hash in raw_recent_collectibles
 652            ]
 653
 654        collectibles: dict[int, int] = {}
 655        for item_hash, mapping in payload["collectibles"].items():
 656            collectibles[int(item_hash)] = int(mapping["state"])
 657
 658        return items.Collectible(
 659            recent_collectibles=recent_collectibles,
 660            collectibles=collectibles,
 661            collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]),
 662            collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]),
 663        )
 664
 665    @staticmethod
 666    def _deserialize_currencies(
 667        payload: typedefs.JSONObject,
 668    ) -> collections.Sequence[items.Currency]:
 669        return [
 670            items.Currency(hash=int(item_hash), amount=int(amount))
 671            for item_hash, amount in payload["itemQuantities"].items()
 672        ]
 673
 674    def deserialize_progressions(
 675        self, payload: typedefs.JSONObject
 676    ) -> progressions.Progression:
 677        return progressions.Progression(
 678            hash=int(payload["progressionHash"]),
 679            level=int(payload["level"]),
 680            cap=int(payload["levelCap"]),
 681            daily_limit=int(payload["dailyLimit"]),
 682            weekly_limit=int(payload["weeklyLimit"]),
 683            current_progress=int(payload["currentProgress"]),
 684            daily_progress=int(payload["dailyProgress"]),
 685            needed=int(payload["progressToNextLevel"]),
 686            next_level=int(payload["nextLevelAt"]),
 687        )
 688
 689    def _deserialize_factions(
 690        self, payload: typedefs.JSONObject
 691    ) -> progressions.Factions:
 692        progs = self.deserialize_progressions(payload)
 693        return progressions.Factions(
 694            hash=progs.hash,
 695            level=progs.level,
 696            cap=progs.cap,
 697            daily_limit=progs.daily_limit,
 698            weekly_limit=progs.weekly_limit,
 699            current_progress=progs.current_progress,
 700            daily_progress=progs.daily_progress,
 701            needed=progs.needed,
 702            next_level=progs.next_level,
 703            faction_hash=payload["factionHash"],
 704            faction_vendor_hash=payload["factionVendorIndex"],
 705        )
 706
 707    def _deserialize_milestone_available_quest(
 708        self, payload: typedefs.JSONObject
 709    ) -> milestones.MilestoneQuest:
 710        return milestones.MilestoneQuest(
 711            item_hash=payload["questItemHash"],
 712            status=self._deserialize_milestone_quest_status(payload["status"]),
 713        )
 714
 715    def _deserialize_milestone_activity(
 716        self, payload: typedefs.JSONObject
 717    ) -> milestones.MilestoneActivity:
 718
 719        phases: typing.Optional[
 720            collections.Sequence[milestones.MilestoneActivityPhase]
 721        ] = None
 722        if raw_phases := payload.get("phases"):
 723            phases = [
 724                milestones.MilestoneActivityPhase(
 725                    is_completed=obj["complete"], hash=obj["phaseHash"]
 726                )
 727                for obj in raw_phases
 728            ]
 729
 730        return milestones.MilestoneActivity(
 731            hash=payload["activityHash"],
 732            challenges=[
 733                self.deserialize_objectives(obj["objective"])
 734                for obj in payload["challenges"]
 735            ],
 736            modifier_hashes=payload.get("modifierHashes"),
 737            boolean_options=payload.get("booleanActivityOptions"),
 738            phases=phases,
 739        )
 740
 741    def _deserialize_milestone_quest_status(
 742        self, payload: typedefs.JSONObject
 743    ) -> milestones.QuestStatus:
 744        return milestones.QuestStatus(
 745            net=self._net,
 746            quest_hash=payload["questHash"],
 747            step_hash=payload["stepHash"],
 748            step_objectives=[
 749                self.deserialize_objectives(objective)
 750                for objective in payload["stepObjectives"]
 751            ],
 752            is_tracked=payload["tracked"],
 753            is_completed=payload["completed"],
 754            started=payload["started"],
 755            item_instance_id=payload["itemInstanceId"],
 756            vendor_hash=payload.get("vendorHash"),
 757            is_redeemed=payload["redeemed"],
 758        )
 759
 760    def _deserialize_milestone_rewards(
 761        self, payload: typedefs.JSONObject
 762    ) -> milestones.MilestoneReward:
 763        return milestones.MilestoneReward(
 764            category_hash=payload["rewardCategoryHash"],
 765            entries=[
 766                milestones.MilestoneRewardEntry(
 767                    entry_hash=entry["rewardEntryHash"],
 768                    is_earned=entry["earned"],
 769                    is_redeemed=entry["redeemed"],
 770                )
 771                for entry in payload["entries"]
 772            ],
 773        )
 774
 775    def deserialize_milestone(
 776        self, payload: typedefs.JSONObject
 777    ) -> milestones.Milestone:
 778        start_date: typing.Optional[datetime.datetime] = None
 779        if raw_start_date := payload.get("startDate"):
 780            start_date = time.clean_date(raw_start_date)
 781
 782        end_date: typing.Optional[datetime.datetime] = None
 783        if raw_end_date := payload.get("endDate"):
 784            end_date = time.clean_date(raw_end_date)
 785
 786        rewards: typing.Optional[
 787            collections.Collection[milestones.MilestoneReward]
 788        ] = None
 789        if raw_rewards := payload.get("rewards"):
 790            rewards = [
 791                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
 792            ]
 793
 794        activities: typing.Optional[
 795            collections.Sequence[milestones.MilestoneActivity]
 796        ] = None
 797        if raw_activities := payload.get("activities"):
 798            activities = [
 799                self._deserialize_milestone_activity(active)
 800                for active in raw_activities
 801            ]
 802
 803        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
 804        if raw_quests := payload.get("availableQuests"):
 805            quests = [
 806                self._deserialize_milestone_available_quest(quest)
 807                for quest in raw_quests
 808            ]
 809
 810        vendors: typing.Optional[
 811            collections.Sequence[milestones.MilestoneVendor]
 812        ] = None
 813        if raw_vendors := payload.get("vendors"):
 814            vendors = [
 815                milestones.MilestoneVendor(
 816                    vendor_hash=vendor["vendorHash"],
 817                    preview_itemhash=vendor.get("previewItemHash"),
 818                )
 819                for vendor in raw_vendors
 820            ]
 821
 822        return milestones.Milestone(
 823            hash=payload["milestoneHash"],
 824            start_date=start_date,
 825            end_date=end_date,
 826            order=payload["order"],
 827            rewards=rewards,
 828            available_quests=quests,
 829            activities=activities,
 830            vendors=vendors,
 831        )
 832
 833    def _deserialize_artifact_tiers(
 834        self, payload: typedefs.JSONObject
 835    ) -> season.ArtifactTier:
 836        return season.ArtifactTier(
 837            hash=payload["tierHash"],
 838            is_unlocked=payload["isUnlocked"],
 839            points_to_unlock=payload["pointsToUnlock"],
 840            items=[
 841                season.ArtifactTierItem(
 842                    hash=item["itemHash"], is_active=item["isActive"]
 843                )
 844                for item in payload["items"]
 845            ],
 846        )
 847
 848    def deserialize_characters(
 849        self, payload: typedefs.JSONObject
 850    ) -> collections.Mapping[int, character.Character]:
 851        return {
 852            int(char_id): self._set_character_attrs(char)
 853            for char_id, char in payload["data"].items()
 854        }
 855
 856    def deserialize_character(
 857        self, payload: typedefs.JSONObject
 858    ) -> character.Character:
 859        return self._set_character_attrs(payload)
 860
 861    def deserialize_character_equipments(
 862        self, payload: typedefs.JSONObject
 863    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
 864        return {
 865            int(char_id): self.deserialize_profile_items(item)
 866            for char_id, item in payload["data"].items()
 867        }
 868
 869    def deserialize_character_activities(
 870        self, payload: typedefs.JSONObject
 871    ) -> collections.Mapping[int, activity.CharacterActivity]:
 872        return {
 873            int(char_id): self.deserialize_character_activity(data)
 874            for char_id, data in payload["data"].items()
 875        }
 876
 877    def deserialize_characters_render_data(
 878        self, payload: typedefs.JSONObject
 879    ) -> collections.Mapping[int, character.RenderedData]:
 880        return {
 881            int(char_id): self.deserialize_character_render_data(data)
 882            for char_id, data in payload["data"].items()
 883        }
 884
 885    def deserialize_character_progressions(
 886        self, payload: typedefs.JSONObject
 887    ) -> character.CharacterProgression:
 888        progressions_ = {
 889            int(prog_id): self.deserialize_progressions(prog)
 890            for prog_id, prog in payload["progressions"].items()
 891        }
 892
 893        factions = {
 894            int(faction_id): self._deserialize_factions(faction)
 895            for faction_id, faction in payload["factions"].items()
 896        }
 897
 898        milestones_ = {
 899            int(milestone_hash): self.deserialize_milestone(milestone)
 900            for milestone_hash, milestone in payload["milestones"].items()
 901        }
 902
 903        uninstanced_item_objectives = {
 904            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
 905            for item_hash, obj in payload["uninstancedItemObjectives"].items()
 906        }
 907
 908        artifact = payload["seasonalArtifact"]
 909        seasonal_artifact = season.CharacterScopedArtifact(
 910            hash=artifact["artifactHash"],
 911            points_used=artifact["pointsUsed"],
 912            reset_count=artifact["resetCount"],
 913            tiers=[
 914                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
 915            ],
 916        )
 917        checklists = payload["checklists"]
 918
 919        return character.CharacterProgression(
 920            progressions=progressions_,
 921            factions=factions,
 922            checklists=checklists,
 923            milestones=milestones_,
 924            seasonal_artifact=seasonal_artifact,
 925            uninstanced_item_objectives=uninstanced_item_objectives,
 926        )
 927
 928    def deserialize_character_progressions_mapping(
 929        self, payload: typedefs.JSONObject
 930    ) -> collections.Mapping[int, character.CharacterProgression]:
 931        character_progressions: collections.Mapping[
 932            int, character.CharacterProgression
 933        ] = {}
 934        for char_id, data in payload["data"].items():
 935            # A little hack to stop mypy complaining about Mapping <-> dict
 936            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
 937        return character_progressions
 938
 939    def deserialize_characters_records(
 940        self,
 941        payload: typedefs.JSONObject,
 942    ) -> collections.Mapping[int, records.CharacterRecord]:
 943
 944        return {
 945            int(rec_id): self.deserialize_character_records(
 946                rec, record_hashes=payload.get("featuredRecordHashes")
 947            )
 948            for rec_id, rec in payload["records"].items()
 949        }
 950
 951    def deserialize_profile_records(
 952        self, payload: typedefs.JSONObject
 953    ) -> collections.Mapping[int, records.Record]:
 954        raw_profile_records = payload["data"]
 955        scores = records.RecordScores(
 956            current_score=raw_profile_records["score"],
 957            legacy_score=raw_profile_records["legacyScore"],
 958            lifetime_score=raw_profile_records["lifetimeScore"],
 959        )
 960        return {
 961            int(record_id): self.deserialize_records(
 962                record,
 963                scores,
 964                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
 965                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
 966            )
 967            for record_id, record in raw_profile_records["records"].items()
 968        }
 969
 970    def _deserialize_craftable_socket_plug(
 971        self, payload: typedefs.JSONObject
 972    ) -> items.CraftableSocketPlug:
 973        return items.CraftableSocketPlug(
 974            item_hash=int(payload["plugItemHash"]),
 975            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 976        )
 977
 978    def _deserialize_craftable_socket(
 979        self, payload: typedefs.JSONObject
 980    ) -> items.CraftableSocket:
 981
 982        plugs: list[items.CraftableSocketPlug] = []
 983        if raw_plug := payload.get("plug"):
 984            plugs.extend(
 985                self._deserialize_craftable_socket_plug(plug) for plug in raw_plug
 986            )
 987
 988        return items.CraftableSocket(
 989            plug_set_hash=int(payload["plugSetHash"]), plugs=plugs
 990        )
 991
 992    def _deserialize_craftable_item(
 993        self, payload: typedefs.JSONObject
 994    ) -> items.CraftableItem:
 995
 996        return items.CraftableItem(
 997            is_visible=payload["visible"],
 998            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 999            sockets=[
1000                self._deserialize_craftable_socket(socket)
1001                for socket in payload["sockets"]
1002            ],
1003        )
1004
1005    def deserialize_craftables_component(
1006        self, payload: typedefs.JSONObject
1007    ) -> components.CraftablesComponent:
1008        return components.CraftablesComponent(
1009            net=self._net,
1010            craftables={
1011                int(item_id): self._deserialize_craftable_item(item)
1012                for item_id, item in payload["craftables"].items()
1013                if item is not None
1014            },
1015            crafting_root_node_hash=payload["craftingRootNodeHash"],
1016        )
1017
1018    def deserialize_components(  # noqa: C901 Too complex.
1019        self, payload: typedefs.JSONObject
1020    ) -> components.Component:
1021
1022        profile_: typing.Optional[profile.Profile] = None
1023        if raw_profile := payload.get("profile"):
1024            profile_ = self.deserialize_profile(raw_profile)
1025
1026        profile_progression: typing.Optional[profile.ProfileProgression] = None
1027        if raw_profile_progression := payload.get("profileProgression"):
1028            profile_progression = self.deserialize_profile_progression(
1029                raw_profile_progression
1030            )
1031
1032        profile_currencies: typing.Optional[
1033            collections.Sequence[profile.ProfileItemImpl]
1034        ] = None
1035        if raw_profile_currencies := payload.get("profileCurrencies"):
1036            if "data" in raw_profile_currencies:
1037                profile_currencies = self.deserialize_profile_items(
1038                    raw_profile_currencies["data"]
1039                )
1040
1041        profile_inventories: typing.Optional[
1042            collections.Sequence[profile.ProfileItemImpl]
1043        ] = None
1044        if raw_profile_inventories := payload.get("profileInventory"):
1045            if "data" in raw_profile_inventories:
1046                profile_inventories = self.deserialize_profile_items(
1047                    raw_profile_inventories["data"]
1048                )
1049
1050        profile_records: typing.Optional[
1051            collections.Mapping[int, records.Record]
1052        ] = None
1053
1054        if raw_profile_records_ := payload.get("profileRecords"):
1055            profile_records = self.deserialize_profile_records(raw_profile_records_)
1056
1057        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1058        if raw_characters := payload.get("characters"):
1059            characters = self.deserialize_characters(raw_characters)
1060
1061        character_records: typing.Optional[
1062            collections.Mapping[int, records.CharacterRecord]
1063        ] = None
1064
1065        if raw_character_records := payload.get("characterRecords"):
1066            # Had to do it in two steps..
1067            to_update: typedefs.JSONObject = {}
1068            for _, data in raw_character_records["data"].items():
1069                for record_id, record in data.items():
1070                    to_update[record_id] = record
1071
1072            character_records = {
1073                int(rec_id): self.deserialize_character_records(
1074                    rec, record_hashes=to_update.get("featuredRecordHashes")
1075                )
1076                for rec_id, rec in to_update["records"].items()
1077            }
1078
1079        character_equipments: typing.Optional[
1080            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1081        ] = None
1082        if raw_character_equips := payload.get("characterEquipment"):
1083            character_equipments = self.deserialize_character_equipments(
1084                raw_character_equips
1085            )
1086
1087        character_inventories: typing.Optional[
1088            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1089        ] = None
1090        if raw_character_inventories := payload.get("characterInventories"):
1091            if "data" in raw_character_inventories:
1092                character_inventories = self.deserialize_character_equipments(
1093                    raw_character_inventories
1094                )
1095
1096        character_activities: typing.Optional[
1097            collections.Mapping[int, activity.CharacterActivity]
1098        ] = None
1099        if raw_char_acts := payload.get("characterActivities"):
1100            character_activities = self.deserialize_character_activities(raw_char_acts)
1101
1102        character_render_data: typing.Optional[
1103            collections.Mapping[int, character.RenderedData]
1104        ] = None
1105        if raw_character_render_data := payload.get("characterRenderData"):
1106            character_render_data = self.deserialize_characters_render_data(
1107                raw_character_render_data
1108            )
1109
1110        character_progressions: typing.Optional[
1111            collections.Mapping[int, character.CharacterProgression]
1112        ] = None
1113
1114        if raw_character_progressions := payload.get("characterProgressions"):
1115            character_progressions = self.deserialize_character_progressions_mapping(
1116                raw_character_progressions
1117            )
1118
1119        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1120        if raw_profile_string_vars := payload.get("profileStringVariables"):
1121            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1122
1123        character_string_vars: typing.Optional[
1124            collections.Mapping[int, collections.Mapping[int, int]]
1125        ] = None
1126        if raw_character_string_vars := payload.get("characterStringVariables"):
1127            character_string_vars = {
1128                int(char_id): data["integerValuesByHash"]
1129                for char_id, data in raw_character_string_vars["data"].items()
1130            }
1131
1132        metrics: typing.Optional[
1133            collections.Sequence[
1134                collections.Mapping[
1135                    int, tuple[bool, typing.Optional[records.Objective]]
1136                ]
1137            ]
1138        ] = None
1139        root_node_hash: typing.Optional[int] = None
1140
1141        if raw_metrics := payload.get("metrics"):
1142            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1143            metrics = [
1144                {
1145                    int(metrics_hash): (
1146                        data["invisible"],
1147                        self.deserialize_objectives(data["objectiveProgress"])
1148                        if "objectiveProgress" in data
1149                        else None,
1150                    )
1151                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1152                }
1153            ]
1154        transitory: typing.Optional[fireteams.FireteamParty] = None
1155        if raw_transitory := payload.get("profileTransitoryData"):
1156            if "data" in raw_transitory:
1157                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1158
1159        item_components: typing.Optional[components.ItemsComponent] = None
1160        if raw_item_components := payload.get("itemComponents"):
1161            item_components = self.deserialize_items_component(raw_item_components)
1162
1163        profile_plugsets: typing.Optional[
1164            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1165        ] = None
1166
1167        if raw_profile_plugs := payload.get("profilePlugSets"):
1168            profile_plugsets = {
1169                int(index): [self.deserialize_plug_item_state(state) for state in data]
1170                for index, data in raw_profile_plugs["data"]["plugs"].items()
1171            }
1172
1173        character_plugsets: typing.Optional[
1174            collections.Mapping[
1175                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1176            ]
1177        ] = None
1178        if raw_char_plugsets := payload.get("characterPlugSets"):
1179            character_plugsets = {
1180                int(char_id): {
1181                    int(index): [
1182                        self.deserialize_plug_item_state(state) for state in data
1183                    ]
1184                    for index, data in inner["plugs"].items()
1185                }
1186                for char_id, inner in raw_char_plugsets["data"].items()
1187            }
1188
1189        character_collectibles: typing.Optional[
1190            collections.Mapping[int, items.Collectible]
1191        ] = None
1192        if raw_character_collectibles := payload.get("characterCollectibles"):
1193            character_collectibles = {
1194                int(char_id): self._deserialize_collectible(data)
1195                for char_id, data in raw_character_collectibles["data"].items()
1196            }
1197
1198        profile_collectibles: typing.Optional[items.Collectible] = None
1199        if raw_profile_collectibles := payload.get("profileCollectibles"):
1200            profile_collectibles = self._deserialize_collectible(
1201                raw_profile_collectibles["data"]
1202            )
1203
1204        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1205        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1206            profile_nodes = {
1207                int(node_hash): self._deserialize_node(node)
1208                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1209            }
1210
1211        character_nodes: typing.Optional[
1212            collections.Mapping[int, collections.Mapping[int, records.Node]]
1213        ] = None
1214        if raw_character_nodes := payload.get("characterPresentationNodes"):
1215            character_nodes = {
1216                int(char_id): {
1217                    int(node_hash): self._deserialize_node(node)
1218                    for node_hash, node in each_character["nodes"].items()
1219                }
1220                for char_id, each_character in raw_character_nodes["data"].items()
1221            }
1222
1223        platform_silver: typing.Optional[
1224            collections.Mapping[str, profile.ProfileItemImpl]
1225        ] = None
1226        if raw_platform_silver := payload.get("platformSilver"):
1227            if "data" in raw_platform_silver:
1228                platform_silver = {
1229                    platform_name: self.deserialize_profile_item(item)
1230                    for platform_name, item in raw_platform_silver["data"][
1231                        "platformSilver"
1232                    ].items()
1233                }
1234
1235        character_currency_lookups: typing.Optional[
1236            collections.Mapping[int, collections.Sequence[items.Currency]]
1237        ] = None
1238        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1239            if "data" in raw_char_lookups:
1240                character_currency_lookups = {
1241                    int(char_id): self._deserialize_currencies(currencie)
1242                    for char_id, currencie in raw_char_lookups["data"].items()
1243                }
1244
1245        character_craftables: typing.Optional[
1246            collections.Mapping[int, components.CraftablesComponent]
1247        ] = None
1248        if raw_character_craftables := payload.get("characterCraftables"):
1249
1250            if "data" in raw_character_craftables:
1251                character_craftables = {
1252                    int(char_id): self.deserialize_craftables_component(craftable)
1253                    for char_id, craftable in raw_character_craftables["data"].items()
1254                }
1255
1256        return components.Component(
1257            profiles=profile_,
1258            profile_progression=profile_progression,
1259            profile_currencies=profile_currencies,
1260            profile_inventories=profile_inventories,
1261            profile_records=profile_records,
1262            characters=characters,
1263            character_records=character_records,
1264            character_equipments=character_equipments,
1265            character_inventories=character_inventories,
1266            character_activities=character_activities,
1267            character_render_data=character_render_data,
1268            character_progressions=character_progressions,
1269            profile_string_variables=profile_string_vars,
1270            character_string_variables=character_string_vars,
1271            metrics=metrics,
1272            root_node_hash=root_node_hash,
1273            transitory=transitory,
1274            item_components=item_components,
1275            profile_plugsets=profile_plugsets,
1276            character_plugsets=character_plugsets,
1277            character_collectibles=character_collectibles,
1278            profile_collectibles=profile_collectibles,
1279            profile_nodes=profile_nodes,
1280            character_nodes=character_nodes,
1281            platform_silver=platform_silver,
1282            character_currency_lookups=character_currency_lookups,
1283            character_craftables=character_craftables,
1284        )
1285
1286    def deserialize_items_component(
1287        self, payload: typedefs.JSONObject
1288    ) -> components.ItemsComponent:
1289        instances: typing.Optional[
1290            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1291        ] = None
1292        if raw_instances := payload.get("instances"):
1293            instances = [
1294                {
1295                    int(ins_id): self.deserialize_instanced_item(item)
1296                    for ins_id, item in raw_instances["data"].items()
1297                }
1298            ]
1299
1300        render_data: typing.Optional[
1301            collections.Mapping[int, tuple[bool, dict[int, int]]]
1302        ] = None
1303        if raw_render_data := payload.get("renderData"):
1304            render_data = {
1305                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1306                for ins_id, data in raw_render_data["data"].items()
1307            }
1308
1309        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1310        if raw_stats := payload.get("stats"):
1311            builder: collections.Mapping[int, items.ItemStatsView] = {}
1312            for ins_id, stat in raw_stats["data"].items():
1313                for _, items_ in stat.items():
1314                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1315            stats = builder
1316
1317        sockets: typing.Optional[
1318            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1319        ] = None
1320        if raw_sockets := payload.get("sockets"):
1321            sockets = {
1322                int(ins_id): [
1323                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1324                ]
1325                for ins_id, item in raw_sockets["data"].items()
1326            }
1327
1328        objeectives: typing.Optional[
1329            collections.Mapping[int, collections.Sequence[records.Objective]]
1330        ] = None
1331        if raw_objectives := payload.get("objectives"):
1332            objeectives = {
1333                int(ins_id): [self.deserialize_objectives(objective)]
1334                for ins_id, data in raw_objectives["data"].items()
1335                for objective in data["objectives"]
1336            }
1337
1338        perks: typing.Optional[
1339            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1340        ] = None
1341        if raw_perks := payload.get("perks"):
1342            perks = {
1343                int(ins_id): [
1344                    self.deserialize_item_perk(perk) for perk in item["perks"]
1345                ]
1346                for ins_id, item in raw_perks["data"].items()
1347            }
1348
1349        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1350        if raw_plug_states := payload.get("plugStates"):
1351            pending_states: list[items.PlugItemState] = []
1352            for _, plug in raw_plug_states["data"].items():
1353                pending_states.append(self.deserialize_plug_item_state(plug))
1354            plug_states = pending_states
1355
1356        reusable_plugs: typing.Optional[
1357            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1358        ] = None
1359        if raw_re_plugs := payload.get("reusablePlugs"):
1360            reusable_plugs = {
1361                int(ins_id): [
1362                    self.deserialize_plug_item_state(state) for state in inner
1363                ]
1364                for ins_id, plug in raw_re_plugs["data"].items()
1365                for inner in list(plug["plugs"].values())
1366            }
1367
1368        plug_objectives: typing.Optional[
1369            collections.Mapping[
1370                int, collections.Mapping[int, collections.Collection[records.Objective]]
1371            ]
1372        ] = None
1373        if raw_plug_objectives := payload.get("plugObjectives"):
1374            plug_objectives = {
1375                int(ins_id): {
1376                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1377                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1378                }
1379                for ins_id, inner in raw_plug_objectives["data"].items()
1380            }
1381
1382        return components.ItemsComponent(
1383            sockets=sockets,
1384            stats=stats,
1385            render_data=render_data,
1386            instances=instances,
1387            objectives=objeectives,
1388            perks=perks,
1389            plug_states=plug_states,
1390            reusable_plugs=reusable_plugs,
1391            plug_objectives=plug_objectives,
1392        )
1393
1394    def deserialize_character_component(  # type: ignore[call-arg]
1395        self, payload: typedefs.JSONObject
1396    ) -> components.CharacterComponent:
1397
1398        character_: typing.Optional[character.Character] = None
1399        if raw_singuler_character := payload.get("character"):
1400            character_ = self.deserialize_character(raw_singuler_character["data"])
1401
1402        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1403        if raw_inventory := payload.get("inventory"):
1404            if "data" in raw_inventory:
1405                inventory = self.deserialize_profile_items(raw_inventory["data"])
1406
1407        activities: typing.Optional[activity.CharacterActivity] = None
1408        if raw_activities := payload.get("activities"):
1409            activities = self.deserialize_character_activity(raw_activities["data"])
1410
1411        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1412        if raw_equipments := payload.get("equipment"):
1413            equipment = self.deserialize_profile_items(raw_equipments["data"])
1414
1415        progressions_: typing.Optional[character.CharacterProgression] = None
1416        if raw_progressions := payload.get("progressions"):
1417            progressions_ = self.deserialize_character_progressions(
1418                raw_progressions["data"]
1419            )
1420
1421        render_data: typing.Optional[character.RenderedData] = None
1422        if raw_render_data := payload.get("renderData"):
1423            render_data = self.deserialize_character_render_data(
1424                raw_render_data["data"]
1425            )
1426
1427        character_records: typing.Optional[
1428            collections.Mapping[int, records.CharacterRecord]
1429        ] = None
1430        if raw_char_records := payload.get("records"):
1431            character_records = self.deserialize_characters_records(
1432                raw_char_records["data"]
1433            )
1434
1435        item_components: typing.Optional[components.ItemsComponent] = None
1436        if raw_item_components := payload.get("itemComponents"):
1437            item_components = self.deserialize_items_component(raw_item_components)
1438
1439        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1440        if raw_nodes := payload.get("presentationNodes"):
1441            nodes = {
1442                int(node_hash): self._deserialize_node(node)
1443                for node_hash, node in raw_nodes["data"]["nodes"].items()
1444            }
1445
1446        collectibles: typing.Optional[items.Collectible] = None
1447        if raw_collectibles := payload.get("collectibles"):
1448            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1449
1450        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1451        if raw_currencies := payload.get("currencyLookups"):
1452            if "data" in raw_currencies:
1453                currency_lookups = self._deserialize_currencies(raw_currencies)
1454
1455        return components.CharacterComponent(
1456            activities=activities,
1457            equipment=equipment,
1458            inventory=inventory,
1459            progressions=progressions_,
1460            render_data=render_data,
1461            character=character_,
1462            character_records=character_records,
1463            profile_records=None,
1464            item_components=item_components,
1465            currency_lookups=currency_lookups,
1466            collectibles=collectibles,
1467            nodes=nodes,
1468        )
1469
1470    def _set_entity_attrs(
1471        self, payload: typedefs.JSONObject, *, key: str = "displayProperties"
1472    ) -> entity.Entity:
1473
1474        name: undefined.UndefinedOr[str] = undefined.Undefined
1475        description: undefined.UndefinedOr[str] = undefined.Undefined
1476
1477        if properties := payload[key]:
1478            if (raw_name := properties["name"]) is not typedefs.Unknown:
1479                name = raw_name
1480
1481            if (
1482                raw_description := properties["description"]
1483            ) and not typedefs.is_unknown(raw_description):
1484                description = raw_description
1485
1486        return entity.Entity(
1487            net=self._net,
1488            hash=payload["hash"],
1489            index=payload["index"],
1490            name=name,
1491            description=description,
1492            has_icon=properties["hasIcon"],
1493            icon=assets.Image(properties["icon"] if "icon" in properties else None),
1494        )
1495
1496    def deserialize_inventory_results(
1497        self, payload: typedefs.JSONObject
1498    ) -> iterators.FlatIterator[entity.SearchableEntity]:
1499        suggested_words: list[str] = payload["suggestedWords"]
1500
1501        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1502            return s if not typedefs.is_unknown(s) else undefined.Undefined
1503
1504        return iterators.FlatIterator(
1505            [
1506                entity.SearchableEntity(
1507                    net=self._net,
1508                    hash=data["hash"],
1509                    entity_type=data["entityType"],
1510                    weight=data["weight"],
1511                    suggested_words=suggested_words,
1512                    name=data["displayProperties"]["name"],
1513                    has_icon=data["displayProperties"]["hasIcon"],
1514                    description=_check_unknown(
1515                        data["displayProperties"]["description"]
1516                    ),
1517                    icon=assets.Image(data["displayProperties"]["icon"]),
1518                )
1519                for data in payload["results"]["results"]
1520            ]
1521        )
1522
1523    def _deserialize_inventory_item_objects(
1524        self, payload: typedefs.JSONObject
1525    ) -> entity.InventoryEntityObjects:
1526        return entity.InventoryEntityObjects(
1527            action=payload.get("action"),
1528            set_data=payload.get("setData"),
1529            stats=payload.get("stats"),
1530            equipping_block=payload.get("equippingBlock"),
1531            translation_block=payload.get("translationBlock"),
1532            preview=payload.get("preview"),
1533            quality=payload.get("quality"),
1534            value=payload.get("value"),
1535            source_data=payload.get("sourceData"),
1536            objectives=payload.get("objectives"),
1537            plug=payload.get("plug"),
1538            metrics=payload.get("metrics"),
1539            gearset=payload.get("gearset"),
1540            sack=payload.get("sack"),
1541            sockets=payload.get("sockets"),
1542            summary=payload.get("summary"),
1543            talent_gird=payload.get("talentGrid"),
1544            investments_stats=payload.get("investmentStats"),
1545            perks=payload.get("perks"),
1546            animations=payload.get("animations", []),
1547            links=payload.get("links", []),
1548        )
1549
1550    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1551        self, payload: typedefs.JSONObject, /
1552    ) -> entity.InventoryEntity:
1553
1554        props = self._set_entity_attrs(payload)
1555        objects = self._deserialize_inventory_item_objects(payload)
1556
1557        collectible_hash: typing.Optional[int] = None
1558        if raw_collectible_hash := payload.get("collectibleHash"):
1559            collectible_hash = int(raw_collectible_hash)
1560
1561        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1562        if raw_second_icon := payload.get("secondaryIcon"):
1563            secondary_icon = assets.Image(raw_second_icon)
1564
1565        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1566        if raw_second_overlay := payload.get("secondaryOverlay"):
1567            secondary_overlay = assets.Image(raw_second_overlay)
1568
1569        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1570        if raw_second_special := payload.get("secondarySpecial"):
1571            secondary_special = assets.Image(raw_second_special)
1572
1573        screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1574        if raw_screenshot := payload.get("screenshot"):
1575            screenshot = assets.Image(raw_screenshot)
1576
1577        watermark_icon: typing.Optional[assets.Image] = None
1578        if raw_watermark_icon := payload.get("iconWatermark"):
1579            watermark_icon = assets.Image(raw_watermark_icon)
1580
1581        watermark_shelved: typing.Optional[assets.Image] = None
1582        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1583            watermark_shelved = assets.Image(raw_watermark_shelved)
1584
1585        about: undefined.UndefinedOr[str] = undefined.Undefined
1586        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1587            raw_about
1588        ):
1589            about = raw_about
1590
1591        ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined
1592        if (
1593            raw_ui_style := payload.get("uiItemDisplayStyle")
1594        ) and not typedefs.is_unknown(raw_ui_style):
1595            ui_item_style = raw_ui_style
1596
1597        tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined
1598        if (
1599            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1600        ) and not typedefs.is_unknown(raw_tier_and_name):
1601            tier_and_name = raw_tier_and_name
1602
1603        type_name: undefined.UndefinedOr[str] = undefined.Undefined
1604        if (
1605            raw_type_name := payload.get("itemTypeDisplayName")
1606        ) and not typedefs.is_unknown(raw_type_name):
1607            type_name = raw_type_name
1608
1609        display_source: undefined.UndefinedOr[str] = undefined.Undefined
1610        if (
1611            raw_display_source := payload.get("displaySource")
1612        ) and not typedefs.is_unknown(raw_display_source):
1613            display_source = raw_display_source
1614
1615        lorehash: typing.Optional[int] = None
1616        if raw_lore_hash := payload.get("loreHash"):
1617            lorehash = int(raw_lore_hash)
1618
1619        summary_hash: typing.Optional[int] = None
1620        if raw_summary_hash := payload.get("summaryItemHash"):
1621            summary_hash = raw_summary_hash
1622
1623        breaker_type_hash: typing.Optional[int] = None
1624        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1625            breaker_type_hash = int(raw_breaker_type_hash)
1626
1627        damage_types: typing.Optional[collections.Sequence[int]] = None
1628        if raw_damage_types := payload.get("damageTypes"):
1629            damage_types = [int(type_) for type_ in raw_damage_types]
1630
1631        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1632        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1633            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1634
1635        default_damagetype_hash: typing.Optional[int] = None
1636        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1637            default_damagetype_hash = int(raw_defaultdmg_hash)
1638
1639        emblem_objective_hash: typing.Optional[int] = None
1640        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1641            emblem_objective_hash = int(raw_emblem_obj_hash)
1642
1643        tier_type: typing.Optional[enums.TierType] = None
1644        tier: typing.Optional[enums.ItemTier] = None
1645        bucket_hash: typing.Optional[int] = None
1646        recovery_hash: typing.Optional[int] = None
1647        tier_name: undefined.UndefinedOr[str] = undefined.Undefined
1648        isinstance_item: bool = False
1649        expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined
1650        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined
1651        suppress_expiration: bool = False
1652        max_stack_size: typing.Optional[int] = None
1653        stack_label: undefined.UndefinedOr[str] = undefined.Undefined
1654
1655        if inventory := payload.get("inventory"):
1656            tier_type = enums.TierType(int(inventory["tierType"]))
1657            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1658            bucket_hash = int(inventory["bucketTypeHash"])
1659            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1660            tier_name = inventory["tierTypeName"]
1661            isinstance_item = inventory["isInstanceItem"]
1662            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1663            max_stack_size = int(inventory["maxStackSize"])
1664
1665            try:
1666                stack_label = inventory["stackUniqueLabel"]
1667            except KeyError:
1668                pass
1669
1670        return entity.InventoryEntity(
1671            net=self._net,
1672            collectible_hash=collectible_hash,
1673            name=props.name,
1674            about=about,
1675            emblem_objective_hash=emblem_objective_hash,
1676            suppress_expiration=suppress_expiration,
1677            max_stack_size=max_stack_size,
1678            stack_label=stack_label,
1679            tier=tier,
1680            tier_type=tier_type,
1681            tier_name=tier_name,
1682            bucket_hash=bucket_hash,
1683            recovery_bucket_hash=recovery_hash,
1684            isinstance_item=isinstance_item,
1685            expire_in_orbit_message=expire_in_orbit_message,
1686            expiration_tooltip=expire_tool_tip,
1687            lore_hash=lorehash,
1688            type_and_tier_name=tier_and_name,
1689            summary_hash=summary_hash,
1690            ui_display_style=ui_item_style,
1691            type_name=type_name,
1692            breaker_type_hash=breaker_type_hash,
1693            description=props.description,
1694            display_source=display_source,
1695            hash=props.hash,
1696            damage_types=damage_types,
1697            index=props.index,
1698            icon=props.icon,
1699            has_icon=props.has_icon,
1700            screenshot=screenshot,
1701            watermark_icon=watermark_icon,
1702            watermark_shelved=watermark_shelved,
1703            secondary_icon=secondary_icon,
1704            secondary_overlay=secondary_overlay,
1705            secondary_special=secondary_special,
1706            type=enums.ItemType(int(payload["itemType"])),
1707            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1708            trait_ids=[trait for trait in payload.get("traitIds", [])],
1709            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1710            item_class=enums.Class(int(payload["classType"])),
1711            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1712            breaker_type=int(payload["breakerType"]),
1713            default_damagetype=int(payload["defaultDamageType"]),
1714            default_damagetype_hash=default_damagetype_hash,
1715            damagetype_hashes=damagetype_hashes,
1716            tooltip_notifications=payload["tooltipNotifications"],
1717            not_transferable=payload["nonTransferrable"],
1718            allow_actions=payload["allowActions"],
1719            is_equippable=payload["equippable"],
1720            objects=objects,
1721            background_colors=payload.get("backgroundColor", {}),
1722            season_hash=payload.get("seasonHash"),
1723            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1724        )
1725
1726    def deserialize_objective_entity(
1727        self, payload: typedefs.JSONObject, /
1728    ) -> entity.ObjectiveEntity:
1729        props = self._set_entity_attrs(payload)
1730        return entity.ObjectiveEntity(
1731            net=self._net,
1732            hash=props.hash,
1733            index=props.index,
1734            description=props.description,
1735            name=props.name,
1736            has_icon=props.has_icon,
1737            icon=props.icon,
1738            unlock_value_hash=payload["unlockValueHash"],
1739            completion_value=payload["completionValue"],
1740            scope=entity.GatingScope(int(payload["scope"])),
1741            location_hash=payload["locationHash"],
1742            allowed_negative_value=payload["allowNegativeValue"],
1743            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1744            counting_downward=payload["isCountingDownward"],
1745            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1746            progress_description=payload["progressDescription"],
1747            perks=payload["perks"],
1748            stats=payload["stats"],
1749            minimum_visibility=payload["minimumVisibilityThreshold"],
1750            allow_over_completion=payload["allowOvercompletion"],
1751            show_value_style=payload["showValueOnComplete"],
1752            display_only_objective=payload["isDisplayOnlyObjective"],
1753            complete_value_style=entity.ValueUIStyle(
1754                int(payload["completedValueStyle"])
1755            ),
1756            progress_value_style=entity.ValueUIStyle(
1757                int(payload["inProgressValueStyle"])
1758            ),
1759            ui_label=payload["uiLabel"],
1760            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1761        )
1762
1763    def _deserialize_activity_values(
1764        self, payload: typedefs.JSONObject, /
1765    ) -> activity.ActivityValues:
1766        team: typing.Optional[int] = None
1767        if raw_team := payload.get("team"):
1768            team = raw_team["basic"]["value"]
1769        return activity.ActivityValues(
1770            assists=payload["assists"]["basic"]["value"],
1771            deaths=payload["deaths"]["basic"]["value"],
1772            kills=payload["kills"]["basic"]["value"],
1773            is_completed=bool(payload["completed"]["basic"]["value"]),
1774            opponents_defeated=payload["opponentsDefeated"]["basic"]["value"],
1775            efficiency=payload["efficiency"]["basic"]["value"],
1776            kd_ratio=payload["killsDeathsRatio"]["basic"]["value"],
1777            kd_assists=payload["killsDeathsAssists"]["basic"]["value"],
1778            score=payload["score"]["basic"]["value"],
1779            duration=payload["activityDurationSeconds"]["basic"]["displayValue"],
1780            team=team,
1781            completion_reason=payload["completionReason"]["basic"]["displayValue"],
1782            fireteam_id=payload["fireteamId"]["basic"]["value"],
1783            start_seconds=payload["startSeconds"]["basic"]["value"],
1784            played_time=payload["timePlayedSeconds"]["basic"]["displayValue"],
1785            player_count=payload["playerCount"]["basic"]["value"],
1786            team_score=payload["teamScore"]["basic"]["value"],
1787        )
1788
1789    def deserialize_activity(
1790        self,
1791        payload: typedefs.JSONObject,
1792        /,
1793    ) -> activity.Activity:
1794        period = time.clean_date(payload["period"])
1795        details = payload["activityDetails"]
1796        ref_id = int(details["referenceId"])
1797        instance_id = int(details["instanceId"])
1798        mode = enums.GameMode(details["mode"])
1799        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1800        is_private = details["isPrivate"]
1801        membership_type = enums.MembershipType(int(details["membershipType"]))
1802
1803        # Since we're using the same fields for post activity method
1804        # this check is required since post activity doesn't values values
1805        values = self._deserialize_activity_values(payload["values"])
1806
1807        return activity.Activity(
1808            net=self._net,
1809            hash=ref_id,
1810            instance_id=instance_id,
1811            mode=mode,
1812            modes=modes,
1813            is_private=is_private,
1814            membership_type=membership_type,
1815            occurred_at=period,
1816            values=values,
1817        )
1818
1819    def deserialize_activities(
1820        self, payload: typedefs.JSONObject
1821    ) -> iterators.FlatIterator[activity.Activity]:
1822        return iterators.FlatIterator(
1823            [
1824                self.deserialize_activity(activity_)
1825                for activity_ in payload["activities"]
1826            ]
1827        )
1828
1829    def deserialize_extended_weapon_values(
1830        self, payload: typedefs.JSONObject
1831    ) -> activity.ExtendedWeaponValues:
1832
1833        assists: typing.Optional[int] = None
1834        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1835            assists = raw_assists["basic"]["value"]
1836        assists_damage: typing.Optional[int] = None
1837
1838        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1839            assists_damage = raw_assists_damage["basic"]["value"]
1840
1841        return activity.ExtendedWeaponValues(
1842            reference_id=int(payload["referenceId"]),
1843            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1844            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1845                "value"
1846            ],
1847            assists=assists,
1848            assists_damage=assists_damage,
1849            precision_kills_percentage=(
1850                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1851                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1852                    "displayValue"
1853                ],
1854            ),
1855        )
1856
1857    def _deserialize_extended_values(
1858        self, payload: typedefs.JSONObject
1859    ) -> activity.ExtendedValues:
1860        weapons: typing.Optional[
1861            collections.Collection[activity.ExtendedWeaponValues]
1862        ] = None
1863
1864        if raw_weapons := payload.get("weapons"):
1865            weapons = [
1866                self.deserialize_extended_weapon_values(value) for value in raw_weapons
1867            ]
1868
1869        return activity.ExtendedValues(
1870            precision_kills=payload["values"]["precisionKills"]["basic"]["value"],
1871            grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"],
1872            melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"],
1873            super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"],
1874            ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"],
1875            weapons=weapons,
1876        )
1877
1878    def deserialize_post_activity_player(
1879        self, payload: typedefs.JSONObject, /
1880    ) -> activity.PostActivityPlayer:
1881        player = payload["player"]
1882
1883        class_hash: typedefs.NoneOr[int] = None
1884        if (class_hash := player.get("classHash")) is not None:
1885            class_hash = class_hash
1886
1887        race_hash: typedefs.NoneOr[int] = None
1888        if (race_hash := player.get("raceHash")) is not None:
1889            race_hash = race_hash
1890
1891        gender_hash: typedefs.NoneOr[int] = None
1892        if (gender_hash := player.get("genderHash")) is not None:
1893            gender_hash = gender_hash
1894
1895        character_class: undefined.UndefinedOr[str] = undefined.Undefined
1896        if (
1897            character_class := player.get("characterClass")
1898        ) and not typedefs.is_unknown(character_class):
1899            character_class = character_class
1900
1901        character_level: typedefs.NoneOr[int] = None
1902        if (character_level := player.get("characterLevel")) is not None:
1903            character_level = character_level
1904
1905        return activity.PostActivityPlayer(
1906            standing=int(payload["standing"]),
1907            score=int(payload["score"]["basic"]["value"]),
1908            character_id=payload["characterId"],
1909            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1910            character_class=character_class,
1911            character_level=character_level,
1912            race_hash=race_hash,
1913            gender_hash=gender_hash,
1914            class_hash=class_hash,
1915            light_level=int(player["lightLevel"]),
1916            emblem_hash=int(player["emblemHash"]),
1917            values=self._deserialize_activity_values(payload["values"]),
1918            extended_values=self._deserialize_extended_values(payload["extended"]),
1919        )
1920
1921    def _deserialize_post_activity_team(
1922        self, payload: typedefs.JSONObject
1923    ) -> activity.PostActivityTeam:
1924        return activity.PostActivityTeam(
1925            id=payload["teamId"],
1926            is_defeated=bool(payload["standing"]["basic"]["value"]),
1927            score=int(payload["score"]["basic"]["value"]),
1928            name=payload["teamName"],
1929        )
1930
1931    def deserialize_post_activity(
1932        self, payload: typedefs.JSONObject
1933    ) -> activity.PostActivity:
1934        period = time.clean_date(payload["period"])
1935        details = payload["activityDetails"]
1936        ref_id = int(details["referenceId"])
1937        instance_id = int(details["instanceId"])
1938        mode = enums.GameMode(details["mode"])
1939        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1940        is_private = details["isPrivate"]
1941        membership_type = enums.MembershipType(int(details["membershipType"]))
1942        return activity.PostActivity(
1943            net=self._net,
1944            hash=ref_id,
1945            membership_type=membership_type,
1946            instance_id=instance_id,
1947            mode=mode,
1948            modes=modes,
1949            is_private=is_private,
1950            occurred_at=period,
1951            starting_phase=int(payload["startingPhaseIndex"]),
1952            players=[
1953                self.deserialize_post_activity_player(player)
1954                for player in payload["entries"]
1955            ],
1956            teams=[
1957                self._deserialize_post_activity_team(team) for team in payload["teams"]
1958            ],
1959        )
1960
1961    def _deserialize_aggregated_activity_values(
1962        self, payload: typedefs.JSONObject
1963    ) -> activity.AggregatedActivityValues:
1964        # This ID is always the same for all aggregated values.
1965        activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"])
1966
1967        return activity.AggregatedActivityValues(
1968            id=activity_id,
1969            fastest_completion_time=(
1970                int(payload["fastestCompletionMsForActivity"]["basic"]["value"]),
1971                payload["fastestCompletionMsForActivity"]["basic"]["displayValue"],
1972            ),
1973            completions=int(payload["activityCompletions"]["basic"]["value"]),
1974            kills=int(payload["activityKills"]["basic"]["value"]),
1975            deaths=int(payload["activityDeaths"]["basic"]["value"]),
1976            assists=int(payload["activityAssists"]["basic"]["value"]),
1977            seconds_played=(
1978                int(payload["activitySecondsPlayed"]["basic"]["value"]),
1979                payload["activitySecondsPlayed"]["basic"]["displayValue"],
1980            ),
1981            wins=int(payload["activityWins"]["basic"]["value"]),
1982            goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]),
1983            special_actions=int(payload["activitySpecialActions"]["basic"]["value"]),
1984            best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]),
1985            best_single_score=int(
1986                payload["activityBestSingleGameScore"]["basic"]["value"]
1987            ),
1988            goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]),
1989            special_score=int(payload["activitySpecialScore"]["basic"]["value"]),
1990            kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]),
1991            kd_ratio=float(
1992                payload["activityKillsDeathsAssists"]["basic"]["displayValue"]
1993            ),
1994            precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]),
1995        )
1996
1997    def deserialize_aggregated_activity(
1998        self, payload: typedefs.JSONObject
1999    ) -> activity.AggregatedActivity:
2000        return activity.AggregatedActivity(
2001            hash=int(payload["activityHash"]),
2002            values=self._deserialize_aggregated_activity_values(payload["values"]),
2003        )
2004
2005    def deserialize_aggregated_activities(
2006        self, payload: typedefs.JSONObject
2007    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
2008        return iterators.FlatIterator(
2009            [
2010                self.deserialize_aggregated_activity(activity)
2011                for activity in payload["activities"]
2012            ]
2013        )
2014
2015    def deserialize_linked_profiles(
2016        self, payload: typedefs.JSONObject
2017    ) -> profile.LinkedProfile:
2018        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
2019        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2020        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2021
2022        if raw_profile := payload.get("profiles"):
2023            for pfile in raw_profile:
2024                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2025
2026        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2027            for raw_error_pfile in raw_profiles_with_errors:
2028                if error_pfile := raw_error_pfile.get("infoCard"):
2029                    error_profiles_vec.append(
2030                        self.deserialize_destiny_membership(error_pfile)
2031                    )
2032
2033        return profile.LinkedProfile(
2034            net=self._net,
2035            bungie=bungie_user,
2036            profiles=profiles_vec,
2037            profiles_with_errors=error_profiles_vec,
2038        )
2039
2040    def deserialize_clan_banners(
2041        self, payload: typedefs.JSONObject
2042    ) -> collections.Sequence[clans.ClanBanner]:
2043        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2044        if banners := payload.get("clanBannerDecals"):
2045            for k, v in banners.items():
2046                banner_obj = clans.ClanBanner(
2047                    id=int(k),
2048                    foreground=assets.Image(v["foregroundPath"]),
2049                    background=assets.Image(v["backgroundPath"]),
2050                )
2051                banners_seq.append(banner_obj)
2052        return banners_seq
2053
2054    def deserialize_public_milestone_content(
2055        self, payload: typedefs.JSONObject
2056    ) -> milestones.MilestoneContent:
2057        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2058        if raw_categories := payload.get("itemCategories"):
2059            for item in raw_categories:
2060                title = undefined.Undefined
2061                if raw_title := item.get("title"):
2062                    if raw_title != typedefs.Unknown:
2063                        title = raw_title
2064                if raw_hashes := item.get("itemHashes"):
2065                    hashes: collections.Sequence[int] = raw_hashes
2066
2067                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2068
2069        about = undefined.Undefined
2070        if (raw_about := payload["about"]) != typedefs.Unknown:
2071            about = raw_about
2072
2073        status = undefined.Undefined
2074        if (raw_status := payload["status"]) != typedefs.Unknown:
2075            status = raw_status
2076
2077        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2078        if raw_tips := payload.get("tips"):
2079            for raw_tip in raw_tips:
2080                if raw_tip == typedefs.Unknown:
2081                    raw_tip = undefined.Undefined
2082                tips.append(raw_tip)
2083
2084        return milestones.MilestoneContent(
2085            about=about, status=status, tips=tips, items=items_categoris
2086        )
2087
2088    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2089        name = undefined.Undefined
2090        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2091            name = raw_name
2092
2093        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2094
2095        if raw_bungie_user := payload.get("bungieNetUser"):
2096            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2097
2098        return friends.Friend(
2099            net=self._net,
2100            id=int(payload["lastSeenAsMembershipId"]),
2101            name=name,
2102            code=payload.get("bungieGlobalDisplayNameCode"),
2103            relationship=enums.Relationship(payload["relationship"]),
2104            user=bungie_user,
2105            online_status=enums.Presence(payload["onlineStatus"]),
2106            online_title=payload["onlineTitle"],
2107            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2108        )
2109
2110    def deserialize_friends(
2111        self, payload: typedefs.JSONObject
2112    ) -> collections.Sequence[friends.Friend]:
2113        mut_seq: typing.MutableSequence[friends.Friend] = []
2114        if raw_friends := payload.get("friends"):
2115            for friend in raw_friends:
2116                mut_seq.append(self.deserialize_friend(friend))
2117        return mut_seq
2118
2119    def deserialize_friend_requests(
2120        self, payload: typedefs.JSONObject
2121    ) -> friends.FriendRequestView:
2122        incoming: typing.MutableSequence[friends.Friend] = []
2123        outgoing: typing.MutableSequence[friends.Friend] = []
2124
2125        if raw_incoming_requests := payload.get("incomingRequests"):
2126            for incoming_request in raw_incoming_requests:
2127                incoming.append(self.deserialize_friend(incoming_request))
2128
2129        if raw_outgoing_requests := payload.get("outgoingRequests"):
2130            for outgoing_request in raw_outgoing_requests:
2131                outgoing.append(self.deserialize_friend(outgoing_request))
2132
2133        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
2134
2135    def _set_fireteam_fields(
2136        self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None
2137    ) -> fireteams.Fireteam:
2138        activity_type = fireteams.FireteamActivity(payload["activityType"])
2139        return fireteams.Fireteam(
2140            id=int(payload["fireteamId"]),
2141            group_id=int(payload["groupId"]),
2142            platform=fireteams.FireteamPlatform(payload["platform"]),
2143            is_immediate=payload["isImmediate"],
2144            activity_type=activity_type,
2145            owner_id=int(payload["ownerMembershipId"]),
2146            player_slot_count=payload["playerSlotCount"],
2147            available_player_slots=payload["availablePlayerSlotCount"],
2148            available_alternate_slots=payload["availableAlternateSlotCount"],
2149            title=payload["title"],
2150            date_created=time.clean_date(payload["dateCreated"]),
2151            is_public=payload["isPublic"],
2152            locale=fireteams.FireteamLanguage(payload["locale"]),
2153            is_valid=payload["isValid"],
2154            last_modified=time.clean_date(payload["datePlayerModified"]),
2155            total_results=total_results or 0,
2156        )
2157
2158    def deserialize_fireteams(
2159        self, payload: typedefs.JSONObject
2160    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2161        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2162
2163        result: list[typedefs.JSONObject]
2164        if not (result := payload["results"]):
2165            return None
2166        for elem in result:
2167            fireteams_.append(
2168                self._set_fireteam_fields(
2169                    elem, total_results=int(payload["totalResults"])
2170                )
2171            )
2172        return fireteams_
2173
2174    def deserialize_fireteam_destiny_users(
2175        self, payload: typedefs.JSONObject
2176    ) -> fireteams.FireteamUser:
2177        destiny_obj = self.deserialize_destiny_membership(payload)
2178        # We could helpers.just return a DestinyMembership object but this is
2179        # missing the fireteam display name and id fields.
2180        return fireteams.FireteamUser(
2181            net=self._net,
2182            id=destiny_obj.id,
2183            code=destiny_obj.code,
2184            icon=destiny_obj.icon,
2185            types=destiny_obj.types,
2186            type=destiny_obj.type,
2187            is_public=destiny_obj.is_public,
2188            crossave_override=destiny_obj.crossave_override,
2189            name=destiny_obj.name,
2190            last_seen_name=destiny_obj.last_seen_name,
2191            fireteam_display_name=payload["FireteamDisplayName"],
2192            fireteam_membership_id=enums.MembershipType(
2193                payload["FireteamMembershipType"]
2194            ),
2195        )
2196
2197    def deserialize_fireteam_members(
2198        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2199    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2200        members_: list[fireteams.FireteamMember] = []
2201        if members := payload.get("Members" if not alternatives else "Alternates"):
2202            for member in members:
2203                bungie_fields = self.deserialize_partial_bungie_user(member)
2204                members_fields = fireteams.FireteamMember(
2205                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2206                    has_microphone=member["hasMicrophone"],
2207                    character_id=int(member["characterId"]),
2208                    date_joined=time.clean_date(member["dateJoined"]),
2209                    last_platform_invite_date=time.clean_date(
2210                        member["lastPlatformInviteAttemptDate"]
2211                    ),
2212                    last_platform_invite_result=int(
2213                        member["lastPlatformInviteAttemptResult"]
2214                    ),
2215                    net=self._net,
2216                    name=bungie_fields.name,
2217                    id=bungie_fields.id,
2218                    icon=bungie_fields.icon,
2219                    is_public=bungie_fields.is_public,
2220                    crossave_override=bungie_fields.crossave_override,
2221                    types=bungie_fields.types,
2222                    type=bungie_fields.type,
2223                )
2224                members_.append(members_fields)
2225        else:
2226            return None
2227        return members_
2228
2229    def deserialize_available_fireteams(
2230        self,
2231        data: typedefs.JSONObject,
2232        *,
2233        no_results: bool = False,
2234    ) -> typing.Union[
2235        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2236    ]:
2237        fireteams_: list[fireteams.AvailableFireteam] = []
2238
2239        # This needs to be used outside the results
2240        # JSON key.
2241        if no_results is True:
2242            payload = data
2243
2244        if result := payload.get("results"):
2245
2246            for fireteam in result:
2247                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2248                fireteams_fields = fireteams.AvailableFireteam(
2249                    id=found_fireteams.id,
2250                    group_id=found_fireteams.group_id,
2251                    platform=found_fireteams.platform,
2252                    activity_type=found_fireteams.activity_type,
2253                    is_immediate=found_fireteams.is_immediate,
2254                    is_public=found_fireteams.is_public,
2255                    is_valid=found_fireteams.is_valid,
2256                    owner_id=found_fireteams.owner_id,
2257                    player_slot_count=found_fireteams.player_slot_count,
2258                    available_player_slots=found_fireteams.available_player_slots,
2259                    available_alternate_slots=found_fireteams.available_alternate_slots,
2260                    title=found_fireteams.title,
2261                    date_created=found_fireteams.date_created,
2262                    locale=found_fireteams.locale,
2263                    last_modified=found_fireteams.last_modified,
2264                    total_results=found_fireteams.total_results,
2265                    members=self.deserialize_fireteam_members(payload),
2266                    alternatives=self.deserialize_fireteam_members(
2267                        payload, alternatives=True
2268                    ),
2269                )
2270            fireteams_.append(fireteams_fields)
2271            if no_results:
2272                return fireteams_fields
2273        return fireteams_
2274
2275    def deserialize_fireteam_party(
2276        self, payload: typedefs.JSONObject
2277    ) -> fireteams.FireteamParty:
2278        last_destination_hash: typing.Optional[int] = None
2279        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2280            last_destination_hash = int(raw_dest_hash)
2281
2282        return fireteams.FireteamParty(
2283            members=[
2284                self._deserialize_fireteam_party_member(member)
2285                for member in payload["partyMembers"]
2286            ],
2287            activity=self._deserialize_fireteam_party_current_activity(
2288                payload["currentActivity"]
2289            ),
2290            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2291            last_destination_hash=last_destination_hash,
2292            tracking=payload["tracking"],
2293        )
2294
2295    def _deserialize_fireteam_party_member(
2296        self, payload: typedefs.JSONObject
2297    ) -> fireteams.FireteamPartyMember:
2298
2299        status = fireteams.FireteamPartyMemberState(payload["status"])
2300        displayname: undefined.UndefinedOr[str] = undefined.Undefined
2301        if raw_name := payload.get("displayName"):
2302            displayname = raw_name
2303
2304        return fireteams.FireteamPartyMember(
2305            membership_id=int(payload["membershipId"]),
2306            emblem_hash=int(payload["emblemHash"]),
2307            status=status,
2308            display_name=displayname,
2309        )
2310
2311    def _deserialize_fireteam_party_current_activity(
2312        self, payload: typedefs.JSONObject
2313    ) -> fireteams.FireteamPartyCurrentActivity:
2314        start_date: typing.Optional[datetime.datetime] = None
2315        if raw_start_date := payload.get("startTime"):
2316            start_date = time.clean_date(raw_start_date)
2317
2318        end_date: typing.Optional[datetime.datetime] = None
2319        if raw_end_date := payload.get("endTime"):
2320            end_date = time.clean_date(raw_end_date)
2321        return fireteams.FireteamPartyCurrentActivity(
2322            start_time=start_date,
2323            end_time=end_date,
2324            score=float(payload["score"]),
2325            highest_opposing_score=float(payload["highestOpposingFactionScore"]),
2326            opponenst_count=int(payload["numberOfOpponents"]),
2327            player_count=int(payload["numberOfPlayers"]),
2328        )
2329
2330    def _deserialize_fireteam_party_settings(
2331        self, payload: typedefs.JSONObject
2332    ) -> fireteams.FireteamPartySettings:
2333        closed_reasons = enums.ClosedReasons(payload["closedReasons"])
2334        return fireteams.FireteamPartySettings(
2335            open_slots=int(payload["openSlots"]),
2336            privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])),
2337            closed_reasons=closed_reasons,
2338        )
2339
2340    def deserialize_seasonal_artifact(
2341        self, payload: typedefs.JSONObject
2342    ) -> season.Artifact:
2343        if raw_artifact := payload.get("seasonalArtifact"):
2344            if points := raw_artifact.get("pointProgression"):
2345                points_prog = progressions.Progression(
2346                    hash=points["progressionHash"],
2347                    level=points["level"],
2348                    cap=points["levelCap"],
2349                    daily_limit=points["dailyLimit"],
2350                    weekly_limit=points["weeklyLimit"],
2351                    current_progress=points["currentProgress"],
2352                    daily_progress=points["dailyProgress"],
2353                    needed=points["progressToNextLevel"],
2354                    next_level=points["nextLevelAt"],
2355                )
2356
2357            if bonus := raw_artifact.get("powerBonusProgression"):
2358                power_bonus_prog = progressions.Progression(
2359                    hash=bonus["progressionHash"],
2360                    level=bonus["level"],
2361                    cap=bonus["levelCap"],
2362                    daily_limit=bonus["dailyLimit"],
2363                    weekly_limit=bonus["weeklyLimit"],
2364                    current_progress=bonus["currentProgress"],
2365                    daily_progress=bonus["dailyProgress"],
2366                    needed=bonus["progressToNextLevel"],
2367                    next_level=bonus["nextLevelAt"],
2368                )
2369            artifact = season.Artifact(
2370                net=self._net,
2371                hash=raw_artifact["artifactHash"],
2372                power_bonus=raw_artifact["powerBonus"],
2373                acquired_points=raw_artifact["pointsAcquired"],
2374                bonus=power_bonus_prog,
2375                points=points_prog,
2376            )
2377        return artifact
2378
2379    def deserialize_profile_progression(
2380        self, payload: typedefs.JSONObject
2381    ) -> profile.ProfileProgression:
2382        return profile.ProfileProgression(
2383            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2384            checklist={
2385                int(check_id): checklists
2386                for check_id, checklists in payload["data"]["checklists"].items()
2387            },
2388        )
2389
2390    def deserialize_instanced_item(
2391        self, payload: typedefs.JSONObject
2392    ) -> items.ItemInstance:
2393        damage_type_hash: typing.Optional[int] = None
2394        if raw_damagetype_hash := payload.get("damageTypeHash"):
2395            damage_type_hash = int(raw_damagetype_hash)
2396
2397        required_hashes: typing.Optional[collections.Collection[int]] = None
2398        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2399            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2400
2401        breaker_type: typing.Optional[items.ItemBreakerType] = None
2402        if raw_break_type := payload.get("breakerType"):
2403            breaker_type = items.ItemBreakerType(int(raw_break_type))
2404
2405        breaker_type_hash: typing.Optional[int] = None
2406        if raw_break_type_hash := payload.get("breakerTypeHash"):
2407            breaker_type_hash = int(raw_break_type_hash)
2408
2409        energy: typing.Optional[items.ItemEnergy] = None
2410        if raw_energy := payload.get("energy"):
2411            energy = self.deserialize_item_energy(raw_energy)
2412
2413        primary_stats = None
2414        if raw_primary_stats := payload.get("primaryStat"):
2415            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2416
2417        return items.ItemInstance(
2418            damage_type=enums.DamageType(int(payload["damageType"])),
2419            damage_type_hash=damage_type_hash,
2420            primary_stat=primary_stats,
2421            item_level=int(payload["itemLevel"]),
2422            quality=int(payload["quality"]),
2423            is_equipped=payload["isEquipped"],
2424            can_equip=payload["canEquip"],
2425            equip_required_level=int(payload["equipRequiredLevel"]),
2426            required_equip_unlock_hashes=required_hashes,
2427            cant_equip_reason=int(payload["cannotEquipReason"]),
2428            breaker_type=breaker_type,
2429            breaker_type_hash=breaker_type_hash,
2430            energy=energy,
2431        )
2432
2433    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2434        energy_hash: typing.Optional[int] = None
2435        if raw_energy_hash := payload.get("energyTypeHash"):
2436            energy_hash = int(raw_energy_hash)
2437
2438        return items.ItemEnergy(
2439            hash=energy_hash,
2440            type=items.ItemEnergyType(int(payload["energyType"])),
2441            capacity=int(payload["energyCapacity"]),
2442            used_energy=int(payload["energyUsed"]),
2443            unused_energy=int(payload["energyUnused"]),
2444        )
2445
2446    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2447        perk_hash: typing.Optional[int] = None
2448        if raw_perk_hash := payload.get("perkHash"):
2449            perk_hash = int(raw_perk_hash)
2450
2451        return items.ItemPerk(
2452            hash=perk_hash,
2453            icon=assets.Image(payload["iconPath"]),
2454            is_active=payload["isActive"],
2455            is_visible=payload["visible"],
2456        )
2457
2458    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2459        plug_hash: typing.Optional[int] = None
2460        if raw_plug_hash := payload.get("plugHash"):
2461            plug_hash = int(raw_plug_hash)
2462
2463        enable_fail_indexes: typing.Optional[list[int]] = None
2464        if raw_indexes := payload.get("enableFailIndexes"):
2465            enable_fail_indexes = [int(index) for index in raw_indexes]
2466
2467        return items.ItemSocket(
2468            plug_hash=plug_hash,
2469            is_enabled=payload["isEnabled"],
2470            enable_fail_indexes=enable_fail_indexes,
2471            is_visible=payload.get("visible"),
2472        )
2473
2474    def deserialize_item_stats_view(
2475        self, payload: typedefs.JSONObject
2476    ) -> items.ItemStatsView:
2477        return items.ItemStatsView(
2478            stat_hash=payload.get("statHash"), value=payload.get("value")
2479        )
2480
2481    def deserialize_plug_item_state(
2482        self, payload: typedefs.JSONObject
2483    ) -> items.PlugItemState:
2484        item_hash: typing.Optional[int] = None
2485        if raw_item_hash := payload.get("plugItemHash"):
2486            item_hash = int(raw_item_hash)
2487
2488        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2489        if raw_fail_indexes := payload.get("insertFailIndexes"):
2490            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2491
2492        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2493        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2494            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2495
2496        return items.PlugItemState(
2497            item_hash=item_hash,
2498            insert_fail_indexes=insert_fail_indexes,
2499            enable_fail_indexes=enable_fail_indexes,
2500            is_enabled=payload["enabled"],
2501            can_insert=payload["canInsert"],
2502        )

The base deserialization factory class for all aiobungie objects.

Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them into a aiobungie.crates Python classes.

Factory(net: aiobungie.traits.Netrunner)
70    def __init__(self, net: traits.Netrunner) -> None:
71        self._net = net
def deserialize_bungie_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.BungieUser:
73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
74        return user.BungieUser(
75            id=int(data["membershipId"]),
76            created_at=time.clean_date(data["firstAccess"]),
77            name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined),
78            is_deleted=data["isDeleted"],
79            about=data["about"],
80            updated_at=time.clean_date(data["lastUpdate"]),
81            psn_name=data.get("psnDisplayName", None),
82            stadia_name=data.get("stadiaDisplayName", None),
83            steam_name=data.get("steamDisplayName", None),
84            twitch_name=data.get("twitchDisplayName", None),
85            blizzard_name=data.get("blizzardDisplayName", None),
86            status=data["statusText"],
87            locale=data["locale"],
88            picture=assets.Image(path=str(data["profilePicturePath"])),
89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
90            unique_name=data.get("uniqueName", None),
91            theme_id=int(data["profileTheme"]),
92            show_activity=bool(data["showActivity"]),
93            theme_name=data["profileThemeName"],
94            display_title=data["userTitleDisplay"],
95        )

Deserialize a raw JSON Bungie.net user only payload into a user object.

This only returns the Bungie.net user and not the Destiny memberships.

Parameters
Returns
def deserialize_partial_bungie_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.PartialBungieUser:
 97    def deserialize_partial_bungie_user(
 98        self, payload: typedefs.JSONObject
 99    ) -> user.PartialBungieUser:
100        return user.PartialBungieUser(
101            net=self._net,
102            types=[
103                enums.MembershipType(type_)
104                for type_ in payload.get("applicableMembershipTypes", [])
105            ],
106            name=payload.get("displayName", undefined.Undefined),
107            id=int(payload["membershipId"]),
108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
109            is_public=payload["isPublic"],
110            icon=assets.Image(payload.get("iconPath", "")),
111            type=enums.MembershipType(payload["membershipType"]),
112        )

Deserialize a raw JSON of a partial bungieNetUserInfo.

A partial user is a bungie.net user payload with missing information from the main BungieUser object.

Parameters
Returns
def deserialize_destiny_membership( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.DestinyMembership:
114    def deserialize_destiny_membership(
115        self, payload: typedefs.JSONObject
116    ) -> user.DestinyMembership:
117        name: undefined.UndefinedOr[str] = undefined.Undefined
118        if (
119            raw_name := payload.get("bungieGlobalDisplayName", "")
120        ) and not typedefs.is_unknown(raw_name):
121            name = raw_name
122
123        return user.DestinyMembership(
124            net=self._net,
125            id=int(payload["membershipId"]),
126            name=name,
127            code=payload.get("bungieGlobalDisplayNameCode", None),
128            last_seen_name=payload.get("LastSeenDisplayName")
129            or payload.get("displayName")  # noqa: W503
130            or "",  # noqa: W503
131            type=enums.MembershipType(payload["membershipType"]),
132            is_public=payload["isPublic"],
133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
134            icon=assets.Image(payload.get("iconPath", "")),
135            types=[
136                enums.MembershipType(type_)
137                for type_ in payload.get("applicableMembershipTypes", [])
138            ],
139        )

Deserialize a raw JSON of destinyUserInfo destiny membership information.

Parameters
Returns
  • aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
def deserialize_destiny_memberships( self, data: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
141    def deserialize_destiny_memberships(
142        self, data: typedefs.JSONArray
143    ) -> collections.Sequence[user.DestinyMembership]:
144        return [self.deserialize_destiny_membership(membership) for membership in data]

Deserialize a raw JSON payload/array of destinyUserInfo.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
def deserialize_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.User:
146    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
147
148        primary_membership_id: typing.Optional[int] = None
149        if raw_primary_id := data.get("primaryMembershipId"):
150            primary_membership_id = int(raw_primary_id)
151
152        return user.User(
153            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
154            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
155            primary_membership_id=primary_membership_id,
156        )

Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.

Parameters
Returns
def deserialize_searched_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.SearchableDestinyUser:
158    def deserialize_searched_user(
159        self, payload: typedefs.JSONObject
160    ) -> user.SearchableDestinyUser:
161        name: undefined.UndefinedOr[str] = undefined.Undefined
162        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
163            raw_name
164        ):
165            name = raw_name
166
167        code: typing.Optional[int] = None
168        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
169            code = int(raw_code)
170
171        bungie_id: typing.Optional[int] = None
172        if raw_bungie_id := payload.get("bungieNetMembershipId"):
173            bungie_id = int(raw_bungie_id)
174
175        return user.SearchableDestinyUser(
176            name=name,
177            code=code,
178            bungie_id=bungie_id,
179            memberships=self.deserialize_destiny_memberships(
180                payload["destinyMemberships"]
181            ),
182        )

Deserialize the results of user search details.

Parameters
Returns
def deserialize_user_credentials( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
184    def deserialize_user_credentials(
185        self, payload: typedefs.JSONArray
186    ) -> collections.Sequence[user.UserCredentials]:
187        return [
188            user.UserCredentials(
189                type=enums.CredentialType(int(creds["credentialType"])),
190                display_name=creds["credentialDisplayName"],
191                is_public=creds["isPublic"],
192                self_as_string=creds.get("credentialAsString", undefined.Undefined),
193            )
194            for creds in payload
195        ]

Deserialize a JSON array of Bungie user credentials.

Parameters
Returns
@staticmethod
def set_themese_attrs( payload: list[typing.Any], /) -> Collection[aiobungie.crates.user.UserThemes]:
197    @staticmethod
198    def set_themese_attrs(
199        payload: typedefs.JSONArray, /
200    ) -> typing.Collection[user.UserThemes]:
201        return [
202            user.UserThemes(
203                id=int(entry["userThemeId"]),
204                name=entry["userThemeName"]
205                if "userThemeName" in entry
206                else undefined.Undefined,
207                description=entry["userThemeDescription"]
208                if "userThemeDescription" in entry
209                else undefined.Undefined,
210            )
211            for entry in payload
212        ]
def deserialize_user_themes( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
214    def deserialize_user_themes(
215        self, payload: typedefs.JSONArray
216    ) -> collections.Sequence[user.UserThemes]:
217        return list(self.set_themese_attrs(payload))

Deserialize a raw JSON array of Bungie user themes.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
def deserialize_clan(self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.Clan:
219    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
220
221        # This is kinda redundant
222        data = payload
223
224        # This is always outside the details.
225        current_user_map: typing.Optional[
226            collections.Mapping[str, clans.ClanMember]
227        ] = None
228        if raw_current_user_map := payload.get("currentUserMemberMap"):
229            current_user_map = {
230                membership_type: self.deserialize_clan_member(membership)
231                for membership_type, membership in raw_current_user_map.items()
232            }
233
234        try:
235            data = payload["detail"]
236        except KeyError:
237            pass
238
239        id = data["groupId"]
240        name = data["name"]
241        created_at = data["creationDate"]
242        member_count = data["memberCount"]
243        about = data["about"]
244        motto = data["motto"]
245        is_public = data["isPublic"]
246        banner = assets.Image(str(data["bannerPath"]))
247        avatar = assets.Image(str(data["avatarPath"]))
248        tags = data["tags"]
249        type = data["groupType"]
250
251        features = data["features"]
252        features_obj = clans.ClanFeatures(
253            max_members=features["maximumMembers"],
254            max_membership_types=features["maximumMembershipsOfGroupType"],
255            capabilities=features["capabilities"],
256            membership_types=features["membershipTypes"],
257            invite_permissions=features["invitePermissionOverride"],
258            update_banner_permissions=features["updateBannerPermissionOverride"],
259            update_culture_permissions=features["updateCulturePermissionOverride"],
260            join_level=features["joinLevel"],
261        )
262
263        information: typedefs.JSONObject = data["clanInfo"]
264        progression: collections.Mapping[int, progressions.Progression] = {
265            int(prog_hash): self.deserialize_progressions(prog)
266            for prog_hash, prog in information["d2ClanProgressions"].items()
267        }
268
269        founder: typedefs.NoneOr[clans.ClanMember] = None
270        if raw_founder := payload.get("founder"):
271            founder = self.deserialize_clan_member(raw_founder)
272
273        return clans.Clan(
274            net=self._net,
275            id=int(id),
276            name=name,
277            type=enums.GroupType(type),
278            created_at=time.clean_date(created_at),
279            member_count=member_count,
280            motto=motto,
281            about=about,
282            is_public=is_public,
283            banner=banner,
284            avatar=avatar,
285            tags=tags,
286            features=features_obj,
287            owner=founder,
288            progressions=progression,
289            call_sign=information["clanCallsign"],
290            banner_data=information["clanBannerData"],
291            chat_security=data["chatSecurity"],
292            conversation_id=int(data["conversationId"]),
293            allow_chat=data["allowChat"],
294            theme=data["theme"],
295            current_user_membership=current_user_map,
296        )

Deserialize a raw JSON payload of Bungie clan information.

Parameters
Returns
def deserialize_clan_member( self, data: dict[str, typing.Any], /) -> aiobungie.crates.clans.ClanMember:
298    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
299        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
300        return clans.ClanMember(
301            net=self._net,
302            last_seen_name=destiny_user.last_seen_name,
303            id=destiny_user.id,
304            name=destiny_user.name,
305            icon=destiny_user.icon,
306            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
307            group_id=int(data["groupId"]),
308            joined_at=time.clean_date(data["joinDate"]),
309            types=destiny_user.types,
310            is_public=destiny_user.is_public,
311            type=destiny_user.type,
312            code=destiny_user.code,
313            is_online=data["isOnline"],
314            crossave_override=destiny_user.crossave_override,
315            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
316            if "bungieNetUserInfo" in data
317            else None,
318            member_type=enums.ClanMemberType(int(data["memberType"])),
319        )

Deserialize a JSON payload of a clan member information.

Parameters
Returns
def deserialize_clan_members( self, data: dict[str, typing.Any], /) -> aiobungie.FlatIterator[aiobungie.crates.clans.ClanMember]:
321    def deserialize_clan_members(
322        self, data: typedefs.JSONObject, /
323    ) -> iterators.FlatIterator[clans.ClanMember]:
324        return iterators.FlatIterator(
325            [self.deserialize_clan_member(member) for member in data["results"]]
326        )

Deserialize a JSON payload of a clan members information.

Parameters
Returns
def deserialize_group_member( self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.GroupMember:
328    def deserialize_group_member(
329        self, payload: typedefs.JSONObject
330    ) -> clans.GroupMember:
331        member = payload["member"]
332        return clans.GroupMember(
333            net=self._net,
334            join_date=time.clean_date(member["joinDate"]),
335            group_id=int(member["groupId"]),
336            member_type=enums.ClanMemberType(member["memberType"]),
337            is_online=member["isOnline"],
338            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
339            inactive_memberships=payload.get("areAllMembershipsInactive", None),
340            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
341            group=self.deserialize_clan(payload["group"]),
342        )

Deserialize a JSON payload of group information for a member.

Parameters
Returns
def deserialize_clan_conversations( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
360    def deserialize_clan_conversations(
361        self, payload: typedefs.JSONArray
362    ) -> collections.Sequence[clans.ClanConversation]:
363        return [self._deserialize_clan_conversation(conv) for conv in payload]

Deserialize a JSON array of a clan conversations information.

Parameters
Returns
def deserialize_app_owner( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.ApplicationOwner:
365    def deserialize_app_owner(
366        self, payload: typedefs.JSONObject
367    ) -> application.ApplicationOwner:
368        return application.ApplicationOwner(
369            net=self._net,
370            name=payload.get("bungieGlobalDisplayName", undefined.Undefined),
371            id=int(payload["membershipId"]),
372            type=enums.MembershipType(payload["membershipType"]),
373            icon=assets.Image(str(payload["iconPath"])),
374            is_public=payload["isPublic"],
375            code=payload.get("bungieGlobalDisplayNameCode", None),
376        )

Deserialize a JSON payload of Bungie Developer portal application owner information.

Parameters
Returns
  • aiobungie.crates.application.ApplicationOwner: An application owner.
def deserialize_app( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.Application:
378    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
379        return application.Application(
380            id=int(payload["applicationId"]),
381            name=payload["name"],
382            link=payload["link"],
383            status=payload["status"],
384            redirect_url=payload.get("redirectUrl", None),
385            created_at=time.clean_date(str(payload["creationDate"])),
386            published_at=time.clean_date(str(payload["firstPublished"])),
387            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
388            scope=payload.get("scope", undefined.Undefined),
389        )

Deserialize a JSON payload of Bungie Developer portal application information.

Parameters
Returns
  • aiobungie.crates.application.Application: An application.
def deserialize_profile( self, payload: dict[str, typing.Any], /) -> Optional[aiobungie.crates.profile.Profile]:
412    def deserialize_profile(
413        self, payload: typedefs.JSONObject, /
414    ) -> typing.Optional[profile.Profile]:
415        if (raw_profile := payload.get("data")) is None:
416            return None
417
418        payload = raw_profile
419        id = int(payload["userInfo"]["membershipId"])
420        name = payload["userInfo"]["displayName"]
421        is_public = payload["userInfo"]["isPublic"]
422        type = enums.MembershipType(payload["userInfo"]["membershipType"])
423        last_played = time.clean_date(str(payload["dateLastPlayed"]))
424        character_ids = [int(cid) for cid in payload["characterIds"]]
425        power_cap = payload["currentSeasonRewardPowerCap"]
426
427        return profile.Profile(
428            id=int(id),
429            name=name,
430            is_public=is_public,
431            type=type,
432            last_played=last_played,
433            character_ids=character_ids,
434            power_cap=power_cap,
435            net=self._net,
436        )

Deserialize a JSON payload of Bungie.net profile information.

Parameters
Returns
def deserialize_profile_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileItemImpl:
438    def deserialize_profile_item(
439        self, payload: typedefs.JSONObject
440    ) -> profile.ProfileItemImpl:
441
442        instance_id: typing.Optional[int] = None
443        if raw_instance_id := payload.get("itemInstanceId"):
444            instance_id = int(raw_instance_id)
445
446        version_number: typing.Optional[int] = None
447        if raw_version := payload.get("versionNumber"):
448            version_number = int(raw_version)
449
450        transfer_status = enums.TransferStatus(payload["transferStatus"])
451
452        return profile.ProfileItemImpl(
453            net=self._net,
454            hash=payload["itemHash"],
455            quantity=payload["quantity"],
456            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
457            location=enums.ItemLocation(payload["location"]),
458            bucket=payload["bucketHash"],
459            transfer_status=transfer_status,
460            lockable=payload["lockable"],
461            state=enums.ItemState(payload["state"]),
462            dismantel_permissions=payload["dismantlePermission"],
463            is_wrapper=payload["isWrapper"],
464            instance_id=instance_id,
465            version_number=version_number,
466            ornament_id=payload.get("overrideStyleItemHash"),
467        )

Deserialize a JSON payload of a singular profile component item.

Parameters
Returns
def deserialize_objectives( self, payload: dict[str, typing.Any]) -> aiobungie.crates.records.Objective:
469    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
470        return records.Objective(
471            net=self._net,
472            hash=payload["objectiveHash"],
473            visible=payload["visible"],
474            complete=payload["complete"],
475            completion_value=payload["completionValue"],
476            progress=payload.get("progress"),
477            destination_hash=payload.get("destinationHash"),
478            activity_hash=payload.get("activityHash"),
479        )

Deserialize a JSON payload of an objective found in a record profile component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
  • aiobungie.crates.records.Objective: A record objective object.
def deserialize_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, **nodes: int) -> aiobungie.crates.records.Record:
481    def deserialize_records(
482        self,
483        payload: typedefs.JSONObject,
484        scores: typing.Optional[records.RecordScores] = None,
485        **nodes: int,
486    ) -> records.Record:
487        objectives: typing.Optional[list[records.Objective]] = None
488        interval_objectives: typing.Optional[list[records.Objective]] = None
489        record_state: typedefs.IntAnd[records.RecordState]
490
491        record_state = records.RecordState(payload["state"])
492
493        if raw_objs := payload.get("objectives"):
494            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
495
496        if raw_interval_objs := payload.get("intervalObjectives"):
497            interval_objectives = [
498                self.deserialize_objectives(obj) for obj in raw_interval_objs
499            ]
500
501        return records.Record(
502            scores=scores,
503            categories_node_hash=nodes.get("categories_hash", undefined.Undefined),
504            seals_node_hash=nodes.get("seals_hash", undefined.Undefined),
505            state=record_state,
506            objectives=objectives,
507            interval_objectives=interval_objectives,
508            redeemed_count=payload.get("intervalsRedeemedCount", 0),
509            completion_times=payload.get("completedCount", None),
510            reward_visibility=payload.get("rewardVisibilty", None),
511        )

Deserialize a JSON object of a profile record component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
  • scores (typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature of aiobungie.crates.CharacterRecord with the record object. As it will always be None in that object.
  • **nodes (int): An int kwargs use to grab the node hashes while deserializing components.
Returns
  • aiobungie.records.Record: A standard implementation of a profile record component.
def deserialize_character_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, record_hashes: Optional[list[int]] = None) -> aiobungie.crates.records.CharacterRecord:
513    def deserialize_character_records(
514        self,
515        payload: typedefs.JSONObject,
516        scores: typing.Optional[records.RecordScores] = None,
517        record_hashes: typing.Optional[list[int]] = None,
518    ) -> records.CharacterRecord:
519
520        record = self.deserialize_records(payload, scores)
521        return records.CharacterRecord(
522            scores=scores,
523            categories_node_hash=record.categories_node_hash,
524            seals_node_hash=record.seals_node_hash,
525            state=record.state,
526            objectives=record.objectives,
527            interval_objectives=record.interval_objectives,
528            redeemed_count=payload.get("intervalsRedeemedCount", 0),
529            completion_times=payload.get("completedCount"),
530            reward_visibility=payload.get("rewardVisibilty"),
531            record_hashes=record_hashes or [],
532        )

Deserialize a JSON object of a profile character record component.

This almost does the same this as deserialize_records but has more fields which can only be found in a character record.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
  • aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
def deserialize_character_dye(self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Dye:
534    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
535        return character.Dye(
536            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
537        )

Deserialize a JSON payload of a character's dye information.

Parameters
Returns
  • aiobungie.crates.character.Dye: Information about a character dye object.
def deserialize_character_customization( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CustomizationOptions:
539    def deserialize_character_customization(
540        self, payload: typedefs.JSONObject
541    ) -> character.CustomizationOptions:
542        return character.CustomizationOptions(
543            personality=payload["personality"],
544            face=payload["face"],
545            skin_color=payload["skinColor"],
546            lip_color=payload["lipColor"],
547            eye_color=payload["eyeColor"],
548            hair_colors=payload.get("hairColors", []),
549            feature_colors=payload.get("featureColors", []),
550            decal_color=payload["decalColor"],
551            wear_helmet=payload["wearHelmet"],
552            hair_index=payload["hairIndex"],
553            feature_index=payload["featureIndex"],
554            decal_index=payload["decalIndex"],
555        )

Deserialize a JSON payload of a character customization information found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
def deserialize_character_minimal_equipments( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.MinimalEquipments:
557    def deserialize_character_minimal_equipments(
558        self, payload: typedefs.JSONObject
559    ) -> character.MinimalEquipments:
560        dyes = None
561        if raw_dyes := payload.get("dyes"):
562            if raw_dyes:
563                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
564        return character.MinimalEquipments(
565            net=self._net, item_hash=payload["itemHash"], dyes=dyes
566        )

Deserialize a singular JSON peer view of equipment found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
def deserialize_character_render_data( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.character.RenderedData:
568    def deserialize_character_render_data(
569        self, payload: typedefs.JSONObject, /
570    ) -> character.RenderedData:
571        return character.RenderedData(
572            net=self._net,
573            customization=self.deserialize_character_customization(
574                payload["customization"]
575            ),
576            custom_dyes=[
577                self.deserialize_character_dye(dye)
578                for dye in payload["customDyes"]
579                if dye
580            ],
581            equipment=[
582                self.deserialize_character_minimal_equipments(equipment)
583                for equipment in payload["peerView"]["equipment"]
584            ],
585        )

Deserialize a JSON payload of a profile character render data component.

Parameters
Returns
def deserialize_available_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AvailableActivity:
587    def deserialize_available_activity(
588        self, payload: typedefs.JSONObject
589    ) -> activity.AvailableActivity:
590        return activity.AvailableActivity(
591            hash=payload["activityHash"],
592            is_new=payload["isNew"],
593            is_completed=payload["isCompleted"],
594            is_visible=payload["isVisible"],
595            display_level=payload.get("displayLevel"),
596            recommended_light=payload.get("recommendedLight"),
597            difficulty=activity.Difficulty(payload["difficultyTier"]),
598            can_join=payload["canJoin"],
599            can_lead=payload["canLead"],
600        )

Deserialize a JSON payload of an available activities.

This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.

Parameters
Returns
def deserialize_character_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.CharacterActivity:
602    def deserialize_character_activity(
603        self, payload: typedefs.JSONObject
604    ) -> activity.CharacterActivity:
605        current_mode: typing.Optional[enums.GameMode] = None
606        if raw_current_mode := payload.get("currentActivityModeType"):
607            current_mode = enums.GameMode(raw_current_mode)
608
609        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
610        if raw_current_modes := payload.get("currentActivityModeTypes"):
611            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
612
613        return activity.CharacterActivity(
614            date_started=time.clean_date(payload["dateActivityStarted"]),
615            current_hash=payload["currentActivityHash"],
616            current_mode_hash=payload["currentActivityModeHash"],
617            current_mode=current_mode,
618            current_mode_hashes=payload.get("currentActivityModeHashes"),
619            current_mode_types=current_mode_types,
620            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
621            last_story_hash=payload["lastCompletedStoryHash"],
622            available_activities=[
623                self.deserialize_available_activity(activity_)
624                for activity_ in payload["availableActivities"]
625            ],
626        )

Deserialize a JSON payload of character activity profile component.

Parameters
Returns
def deserialize_profile_items( self, payload: dict[str, typing.Any], /) -> list[aiobungie.crates.profile.ProfileItemImpl]:
628    def deserialize_profile_items(
629        self, payload: typedefs.JSONObject, /
630    ) -> list[profile.ProfileItemImpl]:
631        return [self.deserialize_profile_item(item) for item in payload["items"]]

Deserialize a JSON payload of profile items component information.

This may deserialize profileInventories or profileCurrencies or any other alternatives.

Parameters
Returns
def deserialize_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.progressions.Progression:
674    def deserialize_progressions(
675        self, payload: typedefs.JSONObject
676    ) -> progressions.Progression:
677        return progressions.Progression(
678            hash=int(payload["progressionHash"]),
679            level=int(payload["level"]),
680            cap=int(payload["levelCap"]),
681            daily_limit=int(payload["dailyLimit"]),
682            weekly_limit=int(payload["weeklyLimit"]),
683            current_progress=int(payload["currentProgress"]),
684            daily_progress=int(payload["dailyProgress"]),
685            needed=int(payload["progressToNextLevel"]),
686            next_level=int(payload["nextLevelAt"]),
687        )
def deserialize_milestone( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.Milestone:
775    def deserialize_milestone(
776        self, payload: typedefs.JSONObject
777    ) -> milestones.Milestone:
778        start_date: typing.Optional[datetime.datetime] = None
779        if raw_start_date := payload.get("startDate"):
780            start_date = time.clean_date(raw_start_date)
781
782        end_date: typing.Optional[datetime.datetime] = None
783        if raw_end_date := payload.get("endDate"):
784            end_date = time.clean_date(raw_end_date)
785
786        rewards: typing.Optional[
787            collections.Collection[milestones.MilestoneReward]
788        ] = None
789        if raw_rewards := payload.get("rewards"):
790            rewards = [
791                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
792            ]
793
794        activities: typing.Optional[
795            collections.Sequence[milestones.MilestoneActivity]
796        ] = None
797        if raw_activities := payload.get("activities"):
798            activities = [
799                self._deserialize_milestone_activity(active)
800                for active in raw_activities
801            ]
802
803        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
804        if raw_quests := payload.get("availableQuests"):
805            quests = [
806                self._deserialize_milestone_available_quest(quest)
807                for quest in raw_quests
808            ]
809
810        vendors: typing.Optional[
811            collections.Sequence[milestones.MilestoneVendor]
812        ] = None
813        if raw_vendors := payload.get("vendors"):
814            vendors = [
815                milestones.MilestoneVendor(
816                    vendor_hash=vendor["vendorHash"],
817                    preview_itemhash=vendor.get("previewItemHash"),
818                )
819                for vendor in raw_vendors
820            ]
821
822        return milestones.Milestone(
823            hash=payload["milestoneHash"],
824            start_date=start_date,
825            end_date=end_date,
826            order=payload["order"],
827            rewards=rewards,
828            available_quests=quests,
829            activities=activities,
830            vendors=vendors,
831        )
def deserialize_characters( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.Character]:
848    def deserialize_characters(
849        self, payload: typedefs.JSONObject
850    ) -> collections.Mapping[int, character.Character]:
851        return {
852            int(char_id): self._set_character_attrs(char)
853            for char_id, char in payload["data"].items()
854        }
def deserialize_character( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Character:
856    def deserialize_character(
857        self, payload: typedefs.JSONObject
858    ) -> character.Character:
859        return self._set_character_attrs(payload)
def deserialize_character_equipments( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, collections.abc.Sequence[aiobungie.crates.profile.ProfileItemImpl]]:
861    def deserialize_character_equipments(
862        self, payload: typedefs.JSONObject
863    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
864        return {
865            int(char_id): self.deserialize_profile_items(item)
866            for char_id, item in payload["data"].items()
867        }
def deserialize_character_activities( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.activity.CharacterActivity]:
869    def deserialize_character_activities(
870        self, payload: typedefs.JSONObject
871    ) -> collections.Mapping[int, activity.CharacterActivity]:
872        return {
873            int(char_id): self.deserialize_character_activity(data)
874            for char_id, data in payload["data"].items()
875        }
def deserialize_characters_render_data( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.RenderedData]:
877    def deserialize_characters_render_data(
878        self, payload: typedefs.JSONObject
879    ) -> collections.Mapping[int, character.RenderedData]:
880        return {
881            int(char_id): self.deserialize_character_render_data(data)
882            for char_id, data in payload["data"].items()
883        }
def deserialize_character_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CharacterProgression:
885    def deserialize_character_progressions(
886        self, payload: typedefs.JSONObject
887    ) -> character.CharacterProgression:
888        progressions_ = {
889            int(prog_id): self.deserialize_progressions(prog)
890            for prog_id, prog in payload["progressions"].items()
891        }
892
893        factions = {
894            int(faction_id): self._deserialize_factions(faction)
895            for faction_id, faction in payload["factions"].items()
896        }
897
898        milestones_ = {
899            int(milestone_hash): self.deserialize_milestone(milestone)
900            for milestone_hash, milestone in payload["milestones"].items()
901        }
902
903        uninstanced_item_objectives = {
904            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
905            for item_hash, obj in payload["uninstancedItemObjectives"].items()
906        }
907
908        artifact = payload["seasonalArtifact"]
909        seasonal_artifact = season.CharacterScopedArtifact(
910            hash=artifact["artifactHash"],
911            points_used=artifact["pointsUsed"],
912            reset_count=artifact["resetCount"],
913            tiers=[
914                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
915            ],
916        )
917        checklists = payload["checklists"]
918
919        return character.CharacterProgression(
920            progressions=progressions_,
921            factions=factions,
922            checklists=checklists,
923            milestones=milestones_,
924            seasonal_artifact=seasonal_artifact,
925            uninstanced_item_objectives=uninstanced_item_objectives,
926        )
def deserialize_character_progressions_mapping( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.CharacterProgression]:
928    def deserialize_character_progressions_mapping(
929        self, payload: typedefs.JSONObject
930    ) -> collections.Mapping[int, character.CharacterProgression]:
931        character_progressions: collections.Mapping[
932            int, character.CharacterProgression
933        ] = {}
934        for char_id, data in payload["data"].items():
935            # A little hack to stop mypy complaining about Mapping <-> dict
936            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
937        return character_progressions
def deserialize_characters_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.CharacterRecord]:
939    def deserialize_characters_records(
940        self,
941        payload: typedefs.JSONObject,
942    ) -> collections.Mapping[int, records.CharacterRecord]:
943
944        return {
945            int(rec_id): self.deserialize_character_records(
946                rec, record_hashes=payload.get("featuredRecordHashes")
947            )
948            for rec_id, rec in payload["records"].items()
949        }
def deserialize_profile_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.Record]:
951    def deserialize_profile_records(
952        self, payload: typedefs.JSONObject
953    ) -> collections.Mapping[int, records.Record]:
954        raw_profile_records = payload["data"]
955        scores = records.RecordScores(
956            current_score=raw_profile_records["score"],
957            legacy_score=raw_profile_records["legacyScore"],
958            lifetime_score=raw_profile_records["lifetimeScore"],
959        )
960        return {
961            int(record_id): self.deserialize_records(
962                record,
963                scores,
964                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
965                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
966            )
967            for record_id, record in raw_profile_records["records"].items()
968        }
def deserialize_craftables_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CraftablesComponent:
1005    def deserialize_craftables_component(
1006        self, payload: typedefs.JSONObject
1007    ) -> components.CraftablesComponent:
1008        return components.CraftablesComponent(
1009            net=self._net,
1010            craftables={
1011                int(item_id): self._deserialize_craftable_item(item)
1012                for item_id, item in payload["craftables"].items()
1013                if item is not None
1014            },
1015            crafting_root_node_hash=payload["craftingRootNodeHash"],
1016        )
def deserialize_components( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.Component:
1018    def deserialize_components(  # noqa: C901 Too complex.
1019        self, payload: typedefs.JSONObject
1020    ) -> components.Component:
1021
1022        profile_: typing.Optional[profile.Profile] = None
1023        if raw_profile := payload.get("profile"):
1024            profile_ = self.deserialize_profile(raw_profile)
1025
1026        profile_progression: typing.Optional[profile.ProfileProgression] = None
1027        if raw_profile_progression := payload.get("profileProgression"):
1028            profile_progression = self.deserialize_profile_progression(
1029                raw_profile_progression
1030            )
1031
1032        profile_currencies: typing.Optional[
1033            collections.Sequence[profile.ProfileItemImpl]
1034        ] = None
1035        if raw_profile_currencies := payload.get("profileCurrencies"):
1036            if "data" in raw_profile_currencies:
1037                profile_currencies = self.deserialize_profile_items(
1038                    raw_profile_currencies["data"]
1039                )
1040
1041        profile_inventories: typing.Optional[
1042            collections.Sequence[profile.ProfileItemImpl]
1043        ] = None
1044        if raw_profile_inventories := payload.get("profileInventory"):
1045            if "data" in raw_profile_inventories:
1046                profile_inventories = self.deserialize_profile_items(
1047                    raw_profile_inventories["data"]
1048                )
1049
1050        profile_records: typing.Optional[
1051            collections.Mapping[int, records.Record]
1052        ] = None
1053
1054        if raw_profile_records_ := payload.get("profileRecords"):
1055            profile_records = self.deserialize_profile_records(raw_profile_records_)
1056
1057        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1058        if raw_characters := payload.get("characters"):
1059            characters = self.deserialize_characters(raw_characters)
1060
1061        character_records: typing.Optional[
1062            collections.Mapping[int, records.CharacterRecord]
1063        ] = None
1064
1065        if raw_character_records := payload.get("characterRecords"):
1066            # Had to do it in two steps..
1067            to_update: typedefs.JSONObject = {}
1068            for _, data in raw_character_records["data"].items():
1069                for record_id, record in data.items():
1070                    to_update[record_id] = record
1071
1072            character_records = {
1073                int(rec_id): self.deserialize_character_records(
1074                    rec, record_hashes=to_update.get("featuredRecordHashes")
1075                )
1076                for rec_id, rec in to_update["records"].items()
1077            }
1078
1079        character_equipments: typing.Optional[
1080            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1081        ] = None
1082        if raw_character_equips := payload.get("characterEquipment"):
1083            character_equipments = self.deserialize_character_equipments(
1084                raw_character_equips
1085            )
1086
1087        character_inventories: typing.Optional[
1088            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1089        ] = None
1090        if raw_character_inventories := payload.get("characterInventories"):
1091            if "data" in raw_character_inventories:
1092                character_inventories = self.deserialize_character_equipments(
1093                    raw_character_inventories
1094                )
1095
1096        character_activities: typing.Optional[
1097            collections.Mapping[int, activity.CharacterActivity]
1098        ] = None
1099        if raw_char_acts := payload.get("characterActivities"):
1100            character_activities = self.deserialize_character_activities(raw_char_acts)
1101
1102        character_render_data: typing.Optional[
1103            collections.Mapping[int, character.RenderedData]
1104        ] = None
1105        if raw_character_render_data := payload.get("characterRenderData"):
1106            character_render_data = self.deserialize_characters_render_data(
1107                raw_character_render_data
1108            )
1109
1110        character_progressions: typing.Optional[
1111            collections.Mapping[int, character.CharacterProgression]
1112        ] = None
1113
1114        if raw_character_progressions := payload.get("characterProgressions"):
1115            character_progressions = self.deserialize_character_progressions_mapping(
1116                raw_character_progressions
1117            )
1118
1119        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1120        if raw_profile_string_vars := payload.get("profileStringVariables"):
1121            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1122
1123        character_string_vars: typing.Optional[
1124            collections.Mapping[int, collections.Mapping[int, int]]
1125        ] = None
1126        if raw_character_string_vars := payload.get("characterStringVariables"):
1127            character_string_vars = {
1128                int(char_id): data["integerValuesByHash"]
1129                for char_id, data in raw_character_string_vars["data"].items()
1130            }
1131
1132        metrics: typing.Optional[
1133            collections.Sequence[
1134                collections.Mapping[
1135                    int, tuple[bool, typing.Optional[records.Objective]]
1136                ]
1137            ]
1138        ] = None
1139        root_node_hash: typing.Optional[int] = None
1140
1141        if raw_metrics := payload.get("metrics"):
1142            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1143            metrics = [
1144                {
1145                    int(metrics_hash): (
1146                        data["invisible"],
1147                        self.deserialize_objectives(data["objectiveProgress"])
1148                        if "objectiveProgress" in data
1149                        else None,
1150                    )
1151                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1152                }
1153            ]
1154        transitory: typing.Optional[fireteams.FireteamParty] = None
1155        if raw_transitory := payload.get("profileTransitoryData"):
1156            if "data" in raw_transitory:
1157                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1158
1159        item_components: typing.Optional[components.ItemsComponent] = None
1160        if raw_item_components := payload.get("itemComponents"):
1161            item_components = self.deserialize_items_component(raw_item_components)
1162
1163        profile_plugsets: typing.Optional[
1164            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1165        ] = None
1166
1167        if raw_profile_plugs := payload.get("profilePlugSets"):
1168            profile_plugsets = {
1169                int(index): [self.deserialize_plug_item_state(state) for state in data]
1170                for index, data in raw_profile_plugs["data"]["plugs"].items()
1171            }
1172
1173        character_plugsets: typing.Optional[
1174            collections.Mapping[
1175                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1176            ]
1177        ] = None
1178        if raw_char_plugsets := payload.get("characterPlugSets"):
1179            character_plugsets = {
1180                int(char_id): {
1181                    int(index): [
1182                        self.deserialize_plug_item_state(state) for state in data
1183                    ]
1184                    for index, data in inner["plugs"].items()
1185                }
1186                for char_id, inner in raw_char_plugsets["data"].items()
1187            }
1188
1189        character_collectibles: typing.Optional[
1190            collections.Mapping[int, items.Collectible]
1191        ] = None
1192        if raw_character_collectibles := payload.get("characterCollectibles"):
1193            character_collectibles = {
1194                int(char_id): self._deserialize_collectible(data)
1195                for char_id, data in raw_character_collectibles["data"].items()
1196            }
1197
1198        profile_collectibles: typing.Optional[items.Collectible] = None
1199        if raw_profile_collectibles := payload.get("profileCollectibles"):
1200            profile_collectibles = self._deserialize_collectible(
1201                raw_profile_collectibles["data"]
1202            )
1203
1204        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1205        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1206            profile_nodes = {
1207                int(node_hash): self._deserialize_node(node)
1208                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1209            }
1210
1211        character_nodes: typing.Optional[
1212            collections.Mapping[int, collections.Mapping[int, records.Node]]
1213        ] = None
1214        if raw_character_nodes := payload.get("characterPresentationNodes"):
1215            character_nodes = {
1216                int(char_id): {
1217                    int(node_hash): self._deserialize_node(node)
1218                    for node_hash, node in each_character["nodes"].items()
1219                }
1220                for char_id, each_character in raw_character_nodes["data"].items()
1221            }
1222
1223        platform_silver: typing.Optional[
1224            collections.Mapping[str, profile.ProfileItemImpl]
1225        ] = None
1226        if raw_platform_silver := payload.get("platformSilver"):
1227            if "data" in raw_platform_silver:
1228                platform_silver = {
1229                    platform_name: self.deserialize_profile_item(item)
1230                    for platform_name, item in raw_platform_silver["data"][
1231                        "platformSilver"
1232                    ].items()
1233                }
1234
1235        character_currency_lookups: typing.Optional[
1236            collections.Mapping[int, collections.Sequence[items.Currency]]
1237        ] = None
1238        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1239            if "data" in raw_char_lookups:
1240                character_currency_lookups = {
1241                    int(char_id): self._deserialize_currencies(currencie)
1242                    for char_id, currencie in raw_char_lookups["data"].items()
1243                }
1244
1245        character_craftables: typing.Optional[
1246            collections.Mapping[int, components.CraftablesComponent]
1247        ] = None
1248        if raw_character_craftables := payload.get("characterCraftables"):
1249
1250            if "data" in raw_character_craftables:
1251                character_craftables = {
1252                    int(char_id): self.deserialize_craftables_component(craftable)
1253                    for char_id, craftable in raw_character_craftables["data"].items()
1254                }
1255
1256        return components.Component(
1257            profiles=profile_,
1258            profile_progression=profile_progression,
1259            profile_currencies=profile_currencies,
1260            profile_inventories=profile_inventories,
1261            profile_records=profile_records,
1262            characters=characters,
1263            character_records=character_records,
1264            character_equipments=character_equipments,
1265            character_inventories=character_inventories,
1266            character_activities=character_activities,
1267            character_render_data=character_render_data,
1268            character_progressions=character_progressions,
1269            profile_string_variables=profile_string_vars,
1270            character_string_variables=character_string_vars,
1271            metrics=metrics,
1272            root_node_hash=root_node_hash,
1273            transitory=transitory,
1274            item_components=item_components,
1275            profile_plugsets=profile_plugsets,
1276            character_plugsets=character_plugsets,
1277            character_collectibles=character_collectibles,
1278            profile_collectibles=profile_collectibles,
1279            profile_nodes=profile_nodes,
1280            character_nodes=character_nodes,
1281            platform_silver=platform_silver,
1282            character_currency_lookups=character_currency_lookups,
1283            character_craftables=character_craftables,
1284        )

Deserialize a JSON payload of Bungie.net profile components information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_items_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.ItemsComponent:
1286    def deserialize_items_component(
1287        self, payload: typedefs.JSONObject
1288    ) -> components.ItemsComponent:
1289        instances: typing.Optional[
1290            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1291        ] = None
1292        if raw_instances := payload.get("instances"):
1293            instances = [
1294                {
1295                    int(ins_id): self.deserialize_instanced_item(item)
1296                    for ins_id, item in raw_instances["data"].items()
1297                }
1298            ]
1299
1300        render_data: typing.Optional[
1301            collections.Mapping[int, tuple[bool, dict[int, int]]]
1302        ] = None
1303        if raw_render_data := payload.get("renderData"):
1304            render_data = {
1305                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1306                for ins_id, data in raw_render_data["data"].items()
1307            }
1308
1309        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1310        if raw_stats := payload.get("stats"):
1311            builder: collections.Mapping[int, items.ItemStatsView] = {}
1312            for ins_id, stat in raw_stats["data"].items():
1313                for _, items_ in stat.items():
1314                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1315            stats = builder
1316
1317        sockets: typing.Optional[
1318            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1319        ] = None
1320        if raw_sockets := payload.get("sockets"):
1321            sockets = {
1322                int(ins_id): [
1323                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1324                ]
1325                for ins_id, item in raw_sockets["data"].items()
1326            }
1327
1328        objeectives: typing.Optional[
1329            collections.Mapping[int, collections.Sequence[records.Objective]]
1330        ] = None
1331        if raw_objectives := payload.get("objectives"):
1332            objeectives = {
1333                int(ins_id): [self.deserialize_objectives(objective)]
1334                for ins_id, data in raw_objectives["data"].items()
1335                for objective in data["objectives"]
1336            }
1337
1338        perks: typing.Optional[
1339            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1340        ] = None
1341        if raw_perks := payload.get("perks"):
1342            perks = {
1343                int(ins_id): [
1344                    self.deserialize_item_perk(perk) for perk in item["perks"]
1345                ]
1346                for ins_id, item in raw_perks["data"].items()
1347            }
1348
1349        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1350        if raw_plug_states := payload.get("plugStates"):
1351            pending_states: list[items.PlugItemState] = []
1352            for _, plug in raw_plug_states["data"].items():
1353                pending_states.append(self.deserialize_plug_item_state(plug))
1354            plug_states = pending_states
1355
1356        reusable_plugs: typing.Optional[
1357            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1358        ] = None
1359        if raw_re_plugs := payload.get("reusablePlugs"):
1360            reusable_plugs = {
1361                int(ins_id): [
1362                    self.deserialize_plug_item_state(state) for state in inner
1363                ]
1364                for ins_id, plug in raw_re_plugs["data"].items()
1365                for inner in list(plug["plugs"].values())
1366            }
1367
1368        plug_objectives: typing.Optional[
1369            collections.Mapping[
1370                int, collections.Mapping[int, collections.Collection[records.Objective]]
1371            ]
1372        ] = None
1373        if raw_plug_objectives := payload.get("plugObjectives"):
1374            plug_objectives = {
1375                int(ins_id): {
1376                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1377                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1378                }
1379                for ins_id, inner in raw_plug_objectives["data"].items()
1380            }
1381
1382        return components.ItemsComponent(
1383            sockets=sockets,
1384            stats=stats,
1385            render_data=render_data,
1386            instances=instances,
1387            objectives=objeectives,
1388            perks=perks,
1389            plug_states=plug_states,
1390            reusable_plugs=reusable_plugs,
1391            plug_objectives=plug_objectives,
1392        )

Deserialize a JSON objects within the itemComponents key.`

def deserialize_character_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CharacterComponent:
1394    def deserialize_character_component(  # type: ignore[call-arg]
1395        self, payload: typedefs.JSONObject
1396    ) -> components.CharacterComponent:
1397
1398        character_: typing.Optional[character.Character] = None
1399        if raw_singuler_character := payload.get("character"):
1400            character_ = self.deserialize_character(raw_singuler_character["data"])
1401
1402        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1403        if raw_inventory := payload.get("inventory"):
1404            if "data" in raw_inventory:
1405                inventory = self.deserialize_profile_items(raw_inventory["data"])
1406
1407        activities: typing.Optional[activity.CharacterActivity] = None
1408        if raw_activities := payload.get("activities"):
1409            activities = self.deserialize_character_activity(raw_activities["data"])
1410
1411        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1412        if raw_equipments := payload.get("equipment"):
1413            equipment = self.deserialize_profile_items(raw_equipments["data"])
1414
1415        progressions_: typing.Optional[character.CharacterProgression] = None
1416        if raw_progressions := payload.get("progressions"):
1417            progressions_ = self.deserialize_character_progressions(
1418                raw_progressions["data"]
1419            )
1420
1421        render_data: typing.Optional[character.RenderedData] = None
1422        if raw_render_data := payload.get("renderData"):
1423            render_data = self.deserialize_character_render_data(
1424                raw_render_data["data"]
1425            )
1426
1427        character_records: typing.Optional[
1428            collections.Mapping[int, records.CharacterRecord]
1429        ] = None
1430        if raw_char_records := payload.get("records"):
1431            character_records = self.deserialize_characters_records(
1432                raw_char_records["data"]
1433            )
1434
1435        item_components: typing.Optional[components.ItemsComponent] = None
1436        if raw_item_components := payload.get("itemComponents"):
1437            item_components = self.deserialize_items_component(raw_item_components)
1438
1439        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1440        if raw_nodes := payload.get("presentationNodes"):
1441            nodes = {
1442                int(node_hash): self._deserialize_node(node)
1443                for node_hash, node in raw_nodes["data"]["nodes"].items()
1444            }
1445
1446        collectibles: typing.Optional[items.Collectible] = None
1447        if raw_collectibles := payload.get("collectibles"):
1448            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1449
1450        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1451        if raw_currencies := payload.get("currencyLookups"):
1452            if "data" in raw_currencies:
1453                currency_lookups = self._deserialize_currencies(raw_currencies)
1454
1455        return components.CharacterComponent(
1456            activities=activities,
1457            equipment=equipment,
1458            inventory=inventory,
1459            progressions=progressions_,
1460            render_data=render_data,
1461            character=character_,
1462            character_records=character_records,
1463            profile_records=None,
1464            item_components=item_components,
1465            currency_lookups=currency_lookups,
1466            collectibles=collectibles,
1467            nodes=nodes,
1468        )

Deserialize a JSON payload of Destiny 2 character component.

Parameters
Returns
def deserialize_inventory_results( self, payload: dict[str, typing.Any]) -> aiobungie.FlatIterator[aiobungie.crates.entity.SearchableEntity]:
1496    def deserialize_inventory_results(
1497        self, payload: typedefs.JSONObject
1498    ) -> iterators.FlatIterator[entity.SearchableEntity]:
1499        suggested_words: list[str] = payload["suggestedWords"]
1500
1501        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1502            return s if not typedefs.is_unknown(s) else undefined.Undefined
1503
1504        return iterators.FlatIterator(
1505            [
1506                entity.SearchableEntity(
1507                    net=self._net,
1508                    hash=data["hash"],
1509                    entity_type=data["entityType"],
1510                    weight=data["weight"],
1511                    suggested_words=suggested_words,
1512                    name=data["displayProperties"]["name"],
1513                    has_icon=data["displayProperties"]["hasIcon"],
1514                    description=_check_unknown(
1515                        data["displayProperties"]["description"]
1516                    ),
1517                    icon=assets.Image(data["displayProperties"]["icon"]),
1518                )
1519                for data in payload["results"]["results"]
1520            ]
1521        )

Deserialize results of searched Destiny2 entities.

Parameters
Returns
def deserialize_inventory_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.InventoryEntity:
1550    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1551        self, payload: typedefs.JSONObject, /
1552    ) -> entity.InventoryEntity:
1553
1554        props = self._set_entity_attrs(payload)
1555        objects = self._deserialize_inventory_item_objects(payload)
1556
1557        collectible_hash: typing.Optional[int] = None
1558        if raw_collectible_hash := payload.get("collectibleHash"):
1559            collectible_hash = int(raw_collectible_hash)
1560
1561        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1562        if raw_second_icon := payload.get("secondaryIcon"):
1563            secondary_icon = assets.Image(raw_second_icon)
1564
1565        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1566        if raw_second_overlay := payload.get("secondaryOverlay"):
1567            secondary_overlay = assets.Image(raw_second_overlay)
1568
1569        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1570        if raw_second_special := payload.get("secondarySpecial"):
1571            secondary_special = assets.Image(raw_second_special)
1572
1573        screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1574        if raw_screenshot := payload.get("screenshot"):
1575            screenshot = assets.Image(raw_screenshot)
1576
1577        watermark_icon: typing.Optional[assets.Image] = None
1578        if raw_watermark_icon := payload.get("iconWatermark"):
1579            watermark_icon = assets.Image(raw_watermark_icon)
1580
1581        watermark_shelved: typing.Optional[assets.Image] = None
1582        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1583            watermark_shelved = assets.Image(raw_watermark_shelved)
1584
1585        about: undefined.UndefinedOr[str] = undefined.Undefined
1586        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1587            raw_about
1588        ):
1589            about = raw_about
1590
1591        ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined
1592        if (
1593            raw_ui_style := payload.get("uiItemDisplayStyle")
1594        ) and not typedefs.is_unknown(raw_ui_style):
1595            ui_item_style = raw_ui_style
1596
1597        tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined
1598        if (
1599            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1600        ) and not typedefs.is_unknown(raw_tier_and_name):
1601            tier_and_name = raw_tier_and_name
1602
1603        type_name: undefined.UndefinedOr[str] = undefined.Undefined
1604        if (
1605            raw_type_name := payload.get("itemTypeDisplayName")
1606        ) and not typedefs.is_unknown(raw_type_name):
1607            type_name = raw_type_name
1608
1609        display_source: undefined.UndefinedOr[str] = undefined.Undefined
1610        if (
1611            raw_display_source := payload.get("displaySource")
1612        ) and not typedefs.is_unknown(raw_display_source):
1613            display_source = raw_display_source
1614
1615        lorehash: typing.Optional[int] = None
1616        if raw_lore_hash := payload.get("loreHash"):
1617            lorehash = int(raw_lore_hash)
1618
1619        summary_hash: typing.Optional[int] = None
1620        if raw_summary_hash := payload.get("summaryItemHash"):
1621            summary_hash = raw_summary_hash
1622
1623        breaker_type_hash: typing.Optional[int] = None
1624        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1625            breaker_type_hash = int(raw_breaker_type_hash)
1626
1627        damage_types: typing.Optional[collections.Sequence[int]] = None
1628        if raw_damage_types := payload.get("damageTypes"):
1629            damage_types = [int(type_) for type_ in raw_damage_types]
1630
1631        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1632        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1633            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1634
1635        default_damagetype_hash: typing.Optional[int] = None
1636        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1637            default_damagetype_hash = int(raw_defaultdmg_hash)
1638
1639        emblem_objective_hash: typing.Optional[int] = None
1640        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1641            emblem_objective_hash = int(raw_emblem_obj_hash)
1642
1643        tier_type: typing.Optional[enums.TierType] = None
1644        tier: typing.Optional[enums.ItemTier] = None
1645        bucket_hash: typing.Optional[int] = None
1646        recovery_hash: typing.Optional[int] = None
1647        tier_name: undefined.UndefinedOr[str] = undefined.Undefined
1648        isinstance_item: bool = False
1649        expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined
1650        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined
1651        suppress_expiration: bool = False
1652        max_stack_size: typing.Optional[int] = None
1653        stack_label: undefined.UndefinedOr[str] = undefined.Undefined
1654
1655        if inventory := payload.get("inventory"):
1656            tier_type = enums.TierType(int(inventory["tierType"]))
1657            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1658            bucket_hash = int(inventory["bucketTypeHash"])
1659            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1660            tier_name = inventory["tierTypeName"]
1661            isinstance_item = inventory["isInstanceItem"]
1662            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1663            max_stack_size = int(inventory["maxStackSize"])
1664
1665            try:
1666                stack_label = inventory["stackUniqueLabel"]
1667            except KeyError:
1668                pass
1669
1670        return entity.InventoryEntity(
1671            net=self._net,
1672            collectible_hash=collectible_hash,
1673            name=props.name,
1674            about=about,
1675            emblem_objective_hash=emblem_objective_hash,
1676            suppress_expiration=suppress_expiration,
1677            max_stack_size=max_stack_size,
1678            stack_label=stack_label,
1679            tier=tier,
1680            tier_type=tier_type,
1681            tier_name=tier_name,
1682            bucket_hash=bucket_hash,
1683            recovery_bucket_hash=recovery_hash,
1684            isinstance_item=isinstance_item,
1685            expire_in_orbit_message=expire_in_orbit_message,
1686            expiration_tooltip=expire_tool_tip,
1687            lore_hash=lorehash,
1688            type_and_tier_name=tier_and_name,
1689            summary_hash=summary_hash,
1690            ui_display_style=ui_item_style,
1691            type_name=type_name,
1692            breaker_type_hash=breaker_type_hash,
1693            description=props.description,
1694            display_source=display_source,
1695            hash=props.hash,
1696            damage_types=damage_types,
1697            index=props.index,
1698            icon=props.icon,
1699            has_icon=props.has_icon,
1700            screenshot=screenshot,
1701            watermark_icon=watermark_icon,
1702            watermark_shelved=watermark_shelved,
1703            secondary_icon=secondary_icon,
1704            secondary_overlay=secondary_overlay,
1705            secondary_special=secondary_special,
1706            type=enums.ItemType(int(payload["itemType"])),
1707            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1708            trait_ids=[trait for trait in payload.get("traitIds", [])],
1709            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1710            item_class=enums.Class(int(payload["classType"])),
1711            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1712            breaker_type=int(payload["breakerType"]),
1713            default_damagetype=int(payload["defaultDamageType"]),
1714            default_damagetype_hash=default_damagetype_hash,
1715            damagetype_hashes=damagetype_hashes,
1716            tooltip_notifications=payload["tooltipNotifications"],
1717            not_transferable=payload["nonTransferrable"],
1718            allow_actions=payload["allowActions"],
1719            is_equippable=payload["equippable"],
1720            objects=objects,
1721            background_colors=payload.get("backgroundColor", {}),
1722            season_hash=payload.get("seasonHash"),
1723            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1724        )

Deserialize a JSON payload of an inventory entity item information.

This can be any item from DestinyInventoryItemDefinition definition.

Parameters
Returns
def deserialize_objective_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.ObjectiveEntity:
1726    def deserialize_objective_entity(
1727        self, payload: typedefs.JSONObject, /
1728    ) -> entity.ObjectiveEntity:
1729        props = self._set_entity_attrs(payload)
1730        return entity.ObjectiveEntity(
1731            net=self._net,
1732            hash=props.hash,
1733            index=props.index,
1734            description=props.description,
1735            name=props.name,
1736            has_icon=props.has_icon,
1737            icon=props.icon,
1738            unlock_value_hash=payload["unlockValueHash"],
1739            completion_value=payload["completionValue"],
1740            scope=entity.GatingScope(int(payload["scope"])),
1741            location_hash=payload["locationHash"],
1742            allowed_negative_value=payload["allowNegativeValue"],
1743            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1744            counting_downward=payload["isCountingDownward"],
1745            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1746            progress_description=payload["progressDescription"],
1747            perks=payload["perks"],
1748            stats=payload["stats"],
1749            minimum_visibility=payload["minimumVisibilityThreshold"],
1750            allow_over_completion=payload["allowOvercompletion"],
1751            show_value_style=payload["showValueOnComplete"],
1752            display_only_objective=payload["isDisplayOnlyObjective"],
1753            complete_value_style=entity.ValueUIStyle(
1754                int(payload["completedValueStyle"])
1755            ),
1756            progress_value_style=entity.ValueUIStyle(
1757                int(payload["inProgressValueStyle"])
1758            ),
1759            ui_label=payload["uiLabel"],
1760            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1761        )

Deserialize a JSON payload of an objective entity information.

Parameters
Returns
def deserialize_activity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.Activity:
1789    def deserialize_activity(
1790        self,
1791        payload: typedefs.JSONObject,
1792        /,
1793    ) -> activity.Activity:
1794        period = time.clean_date(payload["period"])
1795        details = payload["activityDetails"]
1796        ref_id = int(details["referenceId"])
1797        instance_id = int(details["instanceId"])
1798        mode = enums.GameMode(details["mode"])
1799        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1800        is_private = details["isPrivate"]
1801        membership_type = enums.MembershipType(int(details["membershipType"]))
1802
1803        # Since we're using the same fields for post activity method
1804        # this check is required since post activity doesn't values values
1805        values = self._deserialize_activity_values(payload["values"])
1806
1807        return activity.Activity(
1808            net=self._net,
1809            hash=ref_id,
1810            instance_id=instance_id,
1811            mode=mode,
1812            modes=modes,
1813            is_private=is_private,
1814            membership_type=membership_type,
1815            occurred_at=period,
1816            values=values,
1817        )

Deserialize a JSON payload of an activity history information.

Parameters
Returns
def deserialize_activities( self, payload: dict[str, typing.Any]) -> aiobungie.FlatIterator[aiobungie.crates.activity.Activity]:
1819    def deserialize_activities(
1820        self, payload: typedefs.JSONObject
1821    ) -> iterators.FlatIterator[activity.Activity]:
1822        return iterators.FlatIterator(
1823            [
1824                self.deserialize_activity(activity_)
1825                for activity_ in payload["activities"]
1826            ]
1827        )

Deserialize a JSON payload of an array of activity history information.

Parameters
Returns
  • aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: Am iterator over activity objects of the deserialized payload.
def deserialize_extended_weapon_values( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.ExtendedWeaponValues:
1829    def deserialize_extended_weapon_values(
1830        self, payload: typedefs.JSONObject
1831    ) -> activity.ExtendedWeaponValues:
1832
1833        assists: typing.Optional[int] = None
1834        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1835            assists = raw_assists["basic"]["value"]
1836        assists_damage: typing.Optional[int] = None
1837
1838        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1839            assists_damage = raw_assists_damage["basic"]["value"]
1840
1841        return activity.ExtendedWeaponValues(
1842            reference_id=int(payload["referenceId"]),
1843            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1844            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1845                "value"
1846            ],
1847            assists=assists,
1848            assists_damage=assists_damage,
1849            precision_kills_percentage=(
1850                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1851                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1852                    "displayValue"
1853                ],
1854            ),
1855        )

Deserialize values of extended weapons JSON object.

Parameters
Returns
def deserialize_post_activity_player( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.PostActivityPlayer:
1878    def deserialize_post_activity_player(
1879        self, payload: typedefs.JSONObject, /
1880    ) -> activity.PostActivityPlayer:
1881        player = payload["player"]
1882
1883        class_hash: typedefs.NoneOr[int] = None
1884        if (class_hash := player.get("classHash")) is not None:
1885            class_hash = class_hash
1886
1887        race_hash: typedefs.NoneOr[int] = None
1888        if (race_hash := player.get("raceHash")) is not None:
1889            race_hash = race_hash
1890
1891        gender_hash: typedefs.NoneOr[int] = None
1892        if (gender_hash := player.get("genderHash")) is not None:
1893            gender_hash = gender_hash
1894
1895        character_class: undefined.UndefinedOr[str] = undefined.Undefined
1896        if (
1897            character_class := player.get("characterClass")
1898        ) and not typedefs.is_unknown(character_class):
1899            character_class = character_class
1900
1901        character_level: typedefs.NoneOr[int] = None
1902        if (character_level := player.get("characterLevel")) is not None:
1903            character_level = character_level
1904
1905        return activity.PostActivityPlayer(
1906            standing=int(payload["standing"]),
1907            score=int(payload["score"]["basic"]["value"]),
1908            character_id=payload["characterId"],
1909            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1910            character_class=character_class,
1911            character_level=character_level,
1912            race_hash=race_hash,
1913            gender_hash=gender_hash,
1914            class_hash=class_hash,
1915            light_level=int(player["lightLevel"]),
1916            emblem_hash=int(player["emblemHash"]),
1917            values=self._deserialize_activity_values(payload["values"]),
1918            extended_values=self._deserialize_extended_values(payload["extended"]),
1919        )

Deserialize a JSON payload of a post activity player information.

Parameters
Returns
def deserialize_post_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.PostActivity:
1931    def deserialize_post_activity(
1932        self, payload: typedefs.JSONObject
1933    ) -> activity.PostActivity:
1934        period = time.clean_date(payload["period"])
1935        details = payload["activityDetails"]
1936        ref_id = int(details["referenceId"])
1937        instance_id = int(details["instanceId"])
1938        mode = enums.GameMode(details["mode"])
1939        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1940        is_private = details["isPrivate"]
1941        membership_type = enums.MembershipType(int(details["membershipType"]))
1942        return activity.PostActivity(
1943            net=self._net,
1944            hash=ref_id,
1945            membership_type=membership_type,
1946            instance_id=instance_id,
1947            mode=mode,
1948            modes=modes,
1949            is_private=is_private,
1950            occurred_at=period,
1951            starting_phase=int(payload["startingPhaseIndex"]),
1952            players=[
1953                self.deserialize_post_activity_player(player)
1954                for player in payload["entries"]
1955            ],
1956            teams=[
1957                self._deserialize_post_activity_team(team) for team in payload["teams"]
1958            ],
1959        )

Deserialize a JSON payload of a post activity information.

Parameters
Returns
def deserialize_aggregated_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AggregatedActivity:
1997    def deserialize_aggregated_activity(
1998        self, payload: typedefs.JSONObject
1999    ) -> activity.AggregatedActivity:
2000        return activity.AggregatedActivity(
2001            hash=int(payload["activityHash"]),
2002            values=self._deserialize_aggregated_activity_values(payload["values"]),
2003        )

Deserialize a JSON payload of an aggregated activity.

Parameters
Returns
def deserialize_aggregated_activities( self, payload: dict[str, typing.Any]) -> aiobungie.FlatIterator[aiobungie.crates.activity.AggregatedActivity]:
2005    def deserialize_aggregated_activities(
2006        self, payload: typedefs.JSONObject
2007    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
2008        return iterators.FlatIterator(
2009            [
2010                self.deserialize_aggregated_activity(activity)
2011                for activity in payload["activities"]
2012            ]
2013        )

Deserialize a JSON payload of an array of aggregated activities.

Parameters
Returns
def deserialize_linked_profiles( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.LinkedProfile:
2015    def deserialize_linked_profiles(
2016        self, payload: typedefs.JSONObject
2017    ) -> profile.LinkedProfile:
2018        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
2019        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2020        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2021
2022        if raw_profile := payload.get("profiles"):
2023            for pfile in raw_profile:
2024                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2025
2026        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2027            for raw_error_pfile in raw_profiles_with_errors:
2028                if error_pfile := raw_error_pfile.get("infoCard"):
2029                    error_profiles_vec.append(
2030                        self.deserialize_destiny_membership(error_pfile)
2031                    )
2032
2033        return profile.LinkedProfile(
2034            net=self._net,
2035            bungie=bungie_user,
2036            profiles=profiles_vec,
2037            profiles_with_errors=error_profiles_vec,
2038        )

Deserialize a JSON payload of Bungie.net hard linked profile information.

Parameters
Returns
def deserialize_clan_banners( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
2040    def deserialize_clan_banners(
2041        self, payload: typedefs.JSONObject
2042    ) -> collections.Sequence[clans.ClanBanner]:
2043        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2044        if banners := payload.get("clanBannerDecals"):
2045            for k, v in banners.items():
2046                banner_obj = clans.ClanBanner(
2047                    id=int(k),
2048                    foreground=assets.Image(v["foregroundPath"]),
2049                    background=assets.Image(v["backgroundPath"]),
2050                )
2051                banners_seq.append(banner_obj)
2052        return banners_seq

Deserialize a JSON array of a clan banners information.

Parameters
Returns
def deserialize_public_milestone_content( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.MilestoneContent:
2054    def deserialize_public_milestone_content(
2055        self, payload: typedefs.JSONObject
2056    ) -> milestones.MilestoneContent:
2057        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2058        if raw_categories := payload.get("itemCategories"):
2059            for item in raw_categories:
2060                title = undefined.Undefined
2061                if raw_title := item.get("title"):
2062                    if raw_title != typedefs.Unknown:
2063                        title = raw_title
2064                if raw_hashes := item.get("itemHashes"):
2065                    hashes: collections.Sequence[int] = raw_hashes
2066
2067                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2068
2069        about = undefined.Undefined
2070        if (raw_about := payload["about"]) != typedefs.Unknown:
2071            about = raw_about
2072
2073        status = undefined.Undefined
2074        if (raw_status := payload["status"]) != typedefs.Unknown:
2075            status = raw_status
2076
2077        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2078        if raw_tips := payload.get("tips"):
2079            for raw_tip in raw_tips:
2080                if raw_tip == typedefs.Unknown:
2081                    raw_tip = undefined.Undefined
2082                tips.append(raw_tip)
2083
2084        return milestones.MilestoneContent(
2085            about=about, status=status, tips=tips, items=items_categoris
2086        )

Deserialize a JSON payload of milestone content information.

Parameters
Returns
def deserialize_friend( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.friends.Friend:
2088    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2089        name = undefined.Undefined
2090        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2091            name = raw_name
2092
2093        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2094
2095        if raw_bungie_user := payload.get("bungieNetUser"):
2096            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2097
2098        return friends.Friend(
2099            net=self._net,
2100            id=int(payload["lastSeenAsMembershipId"]),
2101            name=name,
2102            code=payload.get("bungieGlobalDisplayNameCode"),
2103            relationship=enums.Relationship(payload["relationship"]),
2104            user=bungie_user,
2105            online_status=enums.Presence(payload["onlineStatus"]),
2106            online_title=payload["onlineTitle"],
2107            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2108        )

Deserialize a JSON payload of a Bungie friend information.

Parameters
Returns
def deserialize_friends( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
2110    def deserialize_friends(
2111        self, payload: typedefs.JSONObject
2112    ) -> collections.Sequence[friends.Friend]:
2113        mut_seq: typing.MutableSequence[friends.Friend] = []
2114        if raw_friends := payload.get("friends"):
2115            for friend in raw_friends:
2116                mut_seq.append(self.deserialize_friend(friend))
2117        return mut_seq

Deserialize a JSON sequence of Bungie friends information.

This is usually used to deserialize the incoming/outgoing friend requests.

Parameters
Returns
def deserialize_friend_requests( self, payload: dict[str, typing.Any]) -> aiobungie.crates.friends.FriendRequestView:
2119    def deserialize_friend_requests(
2120        self, payload: typedefs.JSONObject
2121    ) -> friends.FriendRequestView:
2122        incoming: typing.MutableSequence[friends.Friend] = []
2123        outgoing: typing.MutableSequence[friends.Friend] = []
2124
2125        if raw_incoming_requests := payload.get("incomingRequests"):
2126            for incoming_request in raw_incoming_requests:
2127                incoming.append(self.deserialize_friend(incoming_request))
2128
2129        if raw_outgoing_requests := payload.get("outgoingRequests"):
2130            for outgoing_request in raw_outgoing_requests:
2131                outgoing.append(self.deserialize_friend(outgoing_request))
2132
2133        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)

Deserialize a JSON sequence of Bungie friend requests information.

This is used for incoming/outgoing friend requests.

Parameters
Returns
def deserialize_fireteams( self, payload: dict[str, typing.Any]) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
2158    def deserialize_fireteams(
2159        self, payload: typedefs.JSONObject
2160    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2161        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2162
2163        result: list[typedefs.JSONObject]
2164        if not (result := payload["results"]):
2165            return None
2166        for elem in result:
2167            fireteams_.append(
2168                self._set_fireteam_fields(
2169                    elem, total_results=int(payload["totalResults"])
2170                )
2171            )
2172        return fireteams_

Deserialize a JSON sequence of Bungie fireteams information.

Parameters
Returns
def deserialize_fireteam_destiny_users( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamUser:
2174    def deserialize_fireteam_destiny_users(
2175        self, payload: typedefs.JSONObject
2176    ) -> fireteams.FireteamUser:
2177        destiny_obj = self.deserialize_destiny_membership(payload)
2178        # We could helpers.just return a DestinyMembership object but this is
2179        # missing the fireteam display name and id fields.
2180        return fireteams.FireteamUser(
2181            net=self._net,
2182            id=destiny_obj.id,
2183            code=destiny_obj.code,
2184            icon=destiny_obj.icon,
2185            types=destiny_obj.types,
2186            type=destiny_obj.type,
2187            is_public=destiny_obj.is_public,
2188            crossave_override=destiny_obj.crossave_override,
2189            name=destiny_obj.name,
2190            last_seen_name=destiny_obj.last_seen_name,
2191            fireteam_display_name=payload["FireteamDisplayName"],
2192            fireteam_membership_id=enums.MembershipType(
2193                payload["FireteamMembershipType"]
2194            ),
2195        )

Deserialize a JSON payload of Bungie fireteam destiny users information.

Parameters
Returns
def deserialize_fireteam_members( self, payload: dict[str, typing.Any], *, alternatives: bool = False) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.FireteamMember]]:
2197    def deserialize_fireteam_members(
2198        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2199    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2200        members_: list[fireteams.FireteamMember] = []
2201        if members := payload.get("Members" if not alternatives else "Alternates"):
2202            for member in members:
2203                bungie_fields = self.deserialize_partial_bungie_user(member)
2204                members_fields = fireteams.FireteamMember(
2205                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2206                    has_microphone=member["hasMicrophone"],
2207                    character_id=int(member["characterId"]),
2208                    date_joined=time.clean_date(member["dateJoined"]),
2209                    last_platform_invite_date=time.clean_date(
2210                        member["lastPlatformInviteAttemptDate"]
2211                    ),
2212                    last_platform_invite_result=int(
2213                        member["lastPlatformInviteAttemptResult"]
2214                    ),
2215                    net=self._net,
2216                    name=bungie_fields.name,
2217                    id=bungie_fields.id,
2218                    icon=bungie_fields.icon,
2219                    is_public=bungie_fields.is_public,
2220                    crossave_override=bungie_fields.crossave_override,
2221                    types=bungie_fields.types,
2222                    type=bungie_fields.type,
2223                )
2224                members_.append(members_fields)
2225        else:
2226            return None
2227        return members_

Deserialize a JSON sequence of Bungie fireteam members information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • alternatives (bool): If set to True, Then it will deserialize the alternatives data in the payload. If not the it will just deserialize the members data.
Returns
def deserialize_available_fireteams( self, data: dict[str, typing.Any], *, no_results: bool = False) -> Union[aiobungie.crates.fireteams.AvailableFireteam, collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]:
2229    def deserialize_available_fireteams(
2230        self,
2231        data: typedefs.JSONObject,
2232        *,
2233        no_results: bool = False,
2234    ) -> typing.Union[
2235        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2236    ]:
2237        fireteams_: list[fireteams.AvailableFireteam] = []
2238
2239        # This needs to be used outside the results
2240        # JSON key.
2241        if no_results is True:
2242            payload = data
2243
2244        if result := payload.get("results"):
2245
2246            for fireteam in result:
2247                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2248                fireteams_fields = fireteams.AvailableFireteam(
2249                    id=found_fireteams.id,
2250                    group_id=found_fireteams.group_id,
2251                    platform=found_fireteams.platform,
2252                    activity_type=found_fireteams.activity_type,
2253                    is_immediate=found_fireteams.is_immediate,
2254                    is_public=found_fireteams.is_public,
2255                    is_valid=found_fireteams.is_valid,
2256                    owner_id=found_fireteams.owner_id,
2257                    player_slot_count=found_fireteams.player_slot_count,
2258                    available_player_slots=found_fireteams.available_player_slots,
2259                    available_alternate_slots=found_fireteams.available_alternate_slots,
2260                    title=found_fireteams.title,
2261                    date_created=found_fireteams.date_created,
2262                    locale=found_fireteams.locale,
2263                    last_modified=found_fireteams.last_modified,
2264                    total_results=found_fireteams.total_results,
2265                    members=self.deserialize_fireteam_members(payload),
2266                    alternatives=self.deserialize_fireteam_members(
2267                        payload, alternatives=True
2268                    ),
2269                )
2270            fireteams_.append(fireteams_fields)
2271            if no_results:
2272                return fireteams_fields
2273        return fireteams_

Deserialize a JSON payload of a sequence of/fireteam information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • no_results (bool): Whether to deserialize the data from results in the payload or not.
Returns
  • typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]] # noqa (E501): An available fireteam or a sequence of available fireteam.
def deserialize_fireteam_party( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamParty:
2275    def deserialize_fireteam_party(
2276        self, payload: typedefs.JSONObject
2277    ) -> fireteams.FireteamParty:
2278        last_destination_hash: typing.Optional[int] = None
2279        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2280            last_destination_hash = int(raw_dest_hash)
2281
2282        return fireteams.FireteamParty(
2283            members=[
2284                self._deserialize_fireteam_party_member(member)
2285                for member in payload["partyMembers"]
2286            ],
2287            activity=self._deserialize_fireteam_party_current_activity(
2288                payload["currentActivity"]
2289            ),
2290            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2291            last_destination_hash=last_destination_hash,
2292            tracking=payload["tracking"],
2293        )

Deserialize a JSON payload of profileTransitory component response.

Parameters
Returns
def deserialize_seasonal_artifact(self, payload: dict[str, typing.Any]) -> aiobungie.crates.season.Artifact:
2340    def deserialize_seasonal_artifact(
2341        self, payload: typedefs.JSONObject
2342    ) -> season.Artifact:
2343        if raw_artifact := payload.get("seasonalArtifact"):
2344            if points := raw_artifact.get("pointProgression"):
2345                points_prog = progressions.Progression(
2346                    hash=points["progressionHash"],
2347                    level=points["level"],
2348                    cap=points["levelCap"],
2349                    daily_limit=points["dailyLimit"],
2350                    weekly_limit=points["weeklyLimit"],
2351                    current_progress=points["currentProgress"],
2352                    daily_progress=points["dailyProgress"],
2353                    needed=points["progressToNextLevel"],
2354                    next_level=points["nextLevelAt"],
2355                )
2356
2357            if bonus := raw_artifact.get("powerBonusProgression"):
2358                power_bonus_prog = progressions.Progression(
2359                    hash=bonus["progressionHash"],
2360                    level=bonus["level"],
2361                    cap=bonus["levelCap"],
2362                    daily_limit=bonus["dailyLimit"],
2363                    weekly_limit=bonus["weeklyLimit"],
2364                    current_progress=bonus["currentProgress"],
2365                    daily_progress=bonus["dailyProgress"],
2366                    needed=bonus["progressToNextLevel"],
2367                    next_level=bonus["nextLevelAt"],
2368                )
2369            artifact = season.Artifact(
2370                net=self._net,
2371                hash=raw_artifact["artifactHash"],
2372                power_bonus=raw_artifact["powerBonus"],
2373                acquired_points=raw_artifact["pointsAcquired"],
2374                bonus=power_bonus_prog,
2375                points=points_prog,
2376            )
2377        return artifact

Deserialize a JSON payload of a Destiny 2 seasonal artifact information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_profile_progression( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileProgression:
2379    def deserialize_profile_progression(
2380        self, payload: typedefs.JSONObject
2381    ) -> profile.ProfileProgression:
2382        return profile.ProfileProgression(
2383            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2384            checklist={
2385                int(check_id): checklists
2386                for check_id, checklists in payload["data"]["checklists"].items()
2387            },
2388        )

Deserialize a JSON payload of a profile progression component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_instanced_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemInstance:
2390    def deserialize_instanced_item(
2391        self, payload: typedefs.JSONObject
2392    ) -> items.ItemInstance:
2393        damage_type_hash: typing.Optional[int] = None
2394        if raw_damagetype_hash := payload.get("damageTypeHash"):
2395            damage_type_hash = int(raw_damagetype_hash)
2396
2397        required_hashes: typing.Optional[collections.Collection[int]] = None
2398        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2399            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2400
2401        breaker_type: typing.Optional[items.ItemBreakerType] = None
2402        if raw_break_type := payload.get("breakerType"):
2403            breaker_type = items.ItemBreakerType(int(raw_break_type))
2404
2405        breaker_type_hash: typing.Optional[int] = None
2406        if raw_break_type_hash := payload.get("breakerTypeHash"):
2407            breaker_type_hash = int(raw_break_type_hash)
2408
2409        energy: typing.Optional[items.ItemEnergy] = None
2410        if raw_energy := payload.get("energy"):
2411            energy = self.deserialize_item_energy(raw_energy)
2412
2413        primary_stats = None
2414        if raw_primary_stats := payload.get("primaryStat"):
2415            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2416
2417        return items.ItemInstance(
2418            damage_type=enums.DamageType(int(payload["damageType"])),
2419            damage_type_hash=damage_type_hash,
2420            primary_stat=primary_stats,
2421            item_level=int(payload["itemLevel"]),
2422            quality=int(payload["quality"]),
2423            is_equipped=payload["isEquipped"],
2424            can_equip=payload["canEquip"],
2425            equip_required_level=int(payload["equipRequiredLevel"]),
2426            required_equip_unlock_hashes=required_hashes,
2427            cant_equip_reason=int(payload["cannotEquipReason"]),
2428            breaker_type=breaker_type,
2429            breaker_type_hash=breaker_type_hash,
2430            energy=energy,
2431        )

Deserialize a JSON object into an instanced item.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_item_energy( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemEnergy:
2433    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2434        energy_hash: typing.Optional[int] = None
2435        if raw_energy_hash := payload.get("energyTypeHash"):
2436            energy_hash = int(raw_energy_hash)
2437
2438        return items.ItemEnergy(
2439            hash=energy_hash,
2440            type=items.ItemEnergyType(int(payload["energyType"])),
2441            capacity=int(payload["energyCapacity"]),
2442            used_energy=int(payload["energyUsed"]),
2443            unused_energy=int(payload["energyUnused"]),
2444        )
def deserialize_item_perk(self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemPerk:
2446    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2447        perk_hash: typing.Optional[int] = None
2448        if raw_perk_hash := payload.get("perkHash"):
2449            perk_hash = int(raw_perk_hash)
2450
2451        return items.ItemPerk(
2452            hash=perk_hash,
2453            icon=assets.Image(payload["iconPath"]),
2454            is_active=payload["isActive"],
2455            is_visible=payload["visible"],
2456        )
def deserialize_item_socket( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemSocket:
2458    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2459        plug_hash: typing.Optional[int] = None
2460        if raw_plug_hash := payload.get("plugHash"):
2461            plug_hash = int(raw_plug_hash)
2462
2463        enable_fail_indexes: typing.Optional[list[int]] = None
2464        if raw_indexes := payload.get("enableFailIndexes"):
2465            enable_fail_indexes = [int(index) for index in raw_indexes]
2466
2467        return items.ItemSocket(
2468            plug_hash=plug_hash,
2469            is_enabled=payload["isEnabled"],
2470            enable_fail_indexes=enable_fail_indexes,
2471            is_visible=payload.get("visible"),
2472        )
def deserialize_item_stats_view( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemStatsView:
2474    def deserialize_item_stats_view(
2475        self, payload: typedefs.JSONObject
2476    ) -> items.ItemStatsView:
2477        return items.ItemStatsView(
2478            stat_hash=payload.get("statHash"), value=payload.get("value")
2479        )
def deserialize_plug_item_state( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.PlugItemState:
2481    def deserialize_plug_item_state(
2482        self, payload: typedefs.JSONObject
2483    ) -> items.PlugItemState:
2484        item_hash: typing.Optional[int] = None
2485        if raw_item_hash := payload.get("plugItemHash"):
2486            item_hash = int(raw_item_hash)
2487
2488        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2489        if raw_fail_indexes := payload.get("insertFailIndexes"):
2490            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2491
2492        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2493        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2494            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2495
2496        return items.PlugItemState(
2497            item_hash=item_hash,
2498            insert_fail_indexes=insert_fail_indexes,
2499            enable_fail_indexes=enable_fail_indexes,
2500            is_enabled=payload["enabled"],
2501            can_insert=payload["canInsert"],
2502        )
@typing.final
class FireteamActivity(builtins.int, aiobungie.Enum):
 68@typing.final
 69class FireteamActivity(int, enums.Enum):
 70    """An enum for the fireteam activities."""
 71
 72    ALL = 0
 73    CRUCIBLE = 2
 74    TRIALS_OF_OSIRIS = 3
 75    NIGHTFALL = 4
 76    ANY = 5
 77    GAMBIT = 6
 78    BLIND_WELL = 7
 79    NIGHTMARE_HUNTS = 12
 80    ALTARS_OF_SORROWS = 14
 81    DUNGEON = 15
 82    RAID_LW = 20
 83    RAID_GOS = 21
 84    RAID_DSC = 22
 85    EXO_CHALLENGE = 23
 86    S12_WRATHBORN = 24
 87    EMPIRE_HUNTS = 25
 88    S13_BATTLEGROUNDS = 26
 89    EXOTIC_QUEST = 27
 90    RAID_VOG = 28
 91    S14_EXPUNGE = 30
 92    S15_ASTRAL_ALIGNMENT = 31
 93    S15_SHATTERED_RELAM = 32
 94    SHATTERED_THRONE = 33
 95    PROPHECY = 34
 96    PIT_OF_HERESY = 35
 97    DOE = 36
 98    """Dares of Eternity."""
 99    DUNGEON_GOA = 37
100    """Grasp of Avarice."""
101    VOW_OF_THE_DISCPILE = 38
102    CAMPAIGN = 39
103    WELLSPRING = 40
104    S16_BATTLEGROUNDS = 41
105    S17_NIGHTMARE_CONTAINMENT = 44
106    S17_SEVER = 45

An enum for the fireteam activities.

CRUCIBLE = <FireteamActivity.CRUCIBLE: 2>
TRIALS_OF_OSIRIS = <FireteamActivity.TRIALS_OF_OSIRIS: 3>
NIGHTFALL = <FireteamActivity.NIGHTFALL: 4>
GAMBIT = <FireteamActivity.GAMBIT: 6>
BLIND_WELL = <FireteamActivity.BLIND_WELL: 7>
NIGHTMARE_HUNTS = <FireteamActivity.NIGHTMARE_HUNTS: 12>
ALTARS_OF_SORROWS = <FireteamActivity.ALTARS_OF_SORROWS: 14>
DUNGEON = <FireteamActivity.DUNGEON: 15>
RAID_LW = <FireteamActivity.RAID_LW: 20>
RAID_GOS = <FireteamActivity.RAID_GOS: 21>
RAID_DSC = <FireteamActivity.RAID_DSC: 22>
EXO_CHALLENGE = <FireteamActivity.EXO_CHALLENGE: 23>
S12_WRATHBORN = <FireteamActivity.S12_WRATHBORN: 24>
EMPIRE_HUNTS = <FireteamActivity.EMPIRE_HUNTS: 25>
S13_BATTLEGROUNDS = <FireteamActivity.S13_BATTLEGROUNDS: 26>
EXOTIC_QUEST = <FireteamActivity.EXOTIC_QUEST: 27>
RAID_VOG = <FireteamActivity.RAID_VOG: 28>
S14_EXPUNGE = <FireteamActivity.S14_EXPUNGE: 30>
S15_ASTRAL_ALIGNMENT = <FireteamActivity.S15_ASTRAL_ALIGNMENT: 31>
S15_SHATTERED_RELAM = <FireteamActivity.S15_SHATTERED_RELAM: 32>
SHATTERED_THRONE = <FireteamActivity.SHATTERED_THRONE: 33>
PROPHECY = <FireteamActivity.PROPHECY: 34>
PIT_OF_HERESY = <FireteamActivity.PIT_OF_HERESY: 35>
DOE = <FireteamActivity.DOE: 36>

Dares of Eternity.

DUNGEON_GOA = <FireteamActivity.DUNGEON_GOA: 37>

Grasp of Avarice.

VOW_OF_THE_DISCPILE = <FireteamActivity.VOW_OF_THE_DISCPILE: 38>
CAMPAIGN = <FireteamActivity.CAMPAIGN: 39>
WELLSPRING = <FireteamActivity.WELLSPRING: 40>
S16_BATTLEGROUNDS = <FireteamActivity.S16_BATTLEGROUNDS: 41>
S17_NIGHTMARE_CONTAINMENT = <FireteamActivity.S17_NIGHTMARE_CONTAINMENT: 44>
S17_SEVER = <FireteamActivity.S17_SEVER: 45>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamDate(builtins.int, aiobungie.Enum):
132@typing.final
133class FireteamDate(int, enums.Enum):
134    """An enum for fireteam date ranges."""
135
136    ALL = 0
137    NOW = 1
138    TODAY = 2
139    TWO_DAYS = 3
140    THIS_WEEK = 4

An enum for fireteam date ranges.

ALL = <FireteamDate.ALL: 0>
NOW = <FireteamDate.NOW: 1>
TODAY = <FireteamDate.TODAY: 2>
TWO_DAYS = <FireteamDate.TWO_DAYS: 3>
THIS_WEEK = <FireteamDate.THIS_WEEK: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamLanguage(builtins.str, aiobungie.Enum):
109@typing.final
110class FireteamLanguage(str, enums.Enum):
111    """An enum for fireteams languages filters."""
112
113    ALL = ""
114    ENGLISH = "en"
115    FRENCH = "fr"
116    ESPANOL = "es"
117    DEUTSCH = "de"
118    ITALIAN = "it"
119    JAPANESE = "ja"
120    PORTUGUESE = "pt-br"
121    RUSSIAN = "ru"
122    POLISH = "pl"
123    KOREAN = "ko"
124    # ? China
125    ZH_CHT = "zh-cht"
126    ZH_CHS = "zh-chs"
127
128    def __str__(self) -> str:
129        return str(self.value)

An enum for fireteams languages filters.

ENGLISH = <FireteamLanguage.ENGLISH: en>
FRENCH = <FireteamLanguage.FRENCH: fr>
ESPANOL = <FireteamLanguage.ESPANOL: es>
DEUTSCH = <FireteamLanguage.DEUTSCH: de>
ITALIAN = <FireteamLanguage.ITALIAN: it>
JAPANESE = <FireteamLanguage.JAPANESE: ja>
PORTUGUESE = <FireteamLanguage.PORTUGUESE: pt-br>
RUSSIAN = <FireteamLanguage.RUSSIAN: ru>
POLISH = <FireteamLanguage.POLISH: pl>
KOREAN = <FireteamLanguage.KOREAN: ko>
ZH_CHT = <FireteamLanguage.ZH_CHT: zh-cht>
ZH_CHS = <FireteamLanguage.ZH_CHS: zh-chs>
Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@typing.final
class FireteamPlatform(builtins.int, aiobungie.Enum):
55@typing.final
56class FireteamPlatform(int, enums.Enum):
57    """An enum for fireteam related to bungie fireteams.
58    This is different from the normal `aiobungie.MembershipType`.
59    """
60
61    ANY = 0
62    PSN_NETWORK = 1
63    XBOX_LIVE = 2
64    STEAM = 4
65    STADIA = 5

An enum for fireteam related to bungie fireteams. This is different from the normal aiobungie.MembershipType.

PSN_NETWORK = <FireteamPlatform.PSN_NETWORK: 1>
XBOX_LIVE = <FireteamPlatform.XBOX_LIVE: 2>
STEAM = <FireteamPlatform.STEAM: 4>
STADIA = <FireteamPlatform.STADIA: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Flag(enum.Flag):
102class Flag(__enum.Flag):
103    """Builtin Python enum flag with extra handlings."""
104
105    # Needs to type this here for mypy
106    _value_: int
107
108    @property
109    def name(self) -> str:  # type: ignore[override]
110        if self._name_ is None:
111            self._name_ = f"UNKNOWN {self._value_}"
112
113        return self._name_
114
115    @property
116    def value(self) -> int:  # type: ignore[override]
117        return self._value_
118
119    def __str__(self) -> str:
120        return self.name
121
122    def __repr__(self) -> str:
123        return f"<{type(self).__name__}.{self.name}: {self._value_!s}>"
124
125    def __int__(self) -> int:
126        if isinstance(self.value, _ITERABLE):
127            raise TypeError(
128                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
129            )
130        return int(self.value)
131
132    def __or__(self, other: typing.Union[Flag, int]) -> Flag:
133        return self.__class__(self._value_ | int(other))
134
135    def __xor__(self, other: typing.Union[Flag, int]) -> Flag:
136        return self.__class__(self._value_ ^ int(other))
137
138    def __and__(self, other: typing.Union[Flag, int]) -> Flag:
139        return self.__class__(other & int(other))
140
141    def __invert__(self) -> Flag:
142        return self.__class__(~self._value_)
143
144    def __contains__(self, other: typing.Union[Flag, int]) -> bool:
145        return self.value & int(other) == int(other)

Builtin Python enum flag with extra handlings.

name: str
value: int
class FlatIterator(typing.Generic[~Item]):
 45class FlatIterator(typing.Generic[Item]):
 46    """A Flat, In-Memory iterator for sequenced based data.
 47
 48    Example
 49    -------
 50    ```py
 51    iterator = FlatIterator([1, 2, 3])
 52
 53    # Map the results.
 54    for item in iterator.map(lambda item: item * 2):
 55        print(item)
 56    # 2
 57    # 4
 58
 59    # Indexing is also supported.
 60    print(iterator[0])
 61    # 1
 62
 63    # Normal iteration.
 64    for item in iterator:
 65        print(item)
 66    # 1
 67    # 2
 68    # 3
 69
 70    # Union two iterators.
 71    iterator2 = FlatIterator([4, 5, 6])
 72    final = iterator | iterator2
 73    # <FlatIterator([1, 2, 3, 4, 5, 6])>
 74    ```
 75
 76    Parameters
 77    ----------
 78    items: `collections.Iterable[Item]`
 79        The items to iterate over.
 80    """
 81
 82    __slots__ = ("_items",)
 83
 84    def __init__(self, items: collections.Iterable[Item]) -> None:
 85        self._items = iter(items)
 86
 87    @typing.overload
 88    def collect(self) -> list[Item]:
 89        ...
 90
 91    @typing.overload
 92    def collect(self, casting: _B) -> list[_B]:
 93        ...
 94
 95    def collect(
 96        self, casting: typing.Optional[_B] = None
 97    ) -> typing.Union[list[Item], list[_B]]:
 98        """Collects all items in the iterator into a list and cast them into an object if provided.
 99
100        Example
101        -------
102        >>> iterator = FlatIterator([1, 2, 3])
103        >>> iterator.collect(casting=str)
104        ["1", "2", "3"]
105
106        Parameters
107        ----------
108        casting: `T | None`
109            The type to cast the items to. If `None` is provided, the items will be returned as is.
110
111        Raises
112        ------
113        `StopIteration`
114            If no elements are left in the iterator.
115        """
116        if casting is not None:
117            return typing.cast(list[_B], list(map(casting, self._items)))
118
119        return list(self._items)
120
121    def next(self) -> Item:
122        """Returns the next item in the iterator.
123
124        Example
125        -------
126        ```py
127        iterator = FlatIterator(["1", "2", "3"])
128        item = iterator.next()
129        assert item == "1"
130        item = iterator.next()
131        assert item == "2"
132        ```
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        try:
140            return self.__next__()
141        except StopIteration:
142            self._ok()
143
144    def map(
145        self, predicate: collections.Callable[[Item], OtherItem]
146    ) -> FlatIterator[OtherItem]:
147        """Maps each item in the iterator to its predicated value.
148
149        Example
150        -------
151        ```py
152        iterator = FlatIterator(["1", "2", "3"]).map(lambda value: int(value))
153        print(iterator)
154        # <FlatIterator([1, 2, 3])>
155        ```
156
157        Parameters
158        ----------
159        predicate: `collections.Callable[[Item], OtherItem]`
160            The function to map each item in the iterator to its predicated value.
161
162        Returns
163        -------
164        `FlatIterator[OtherItem]`
165            The mapped iterator.
166
167        Raises
168        ------
169        `StopIteration`
170            If no elements are left in the iterator.
171        """
172        return FlatIterator(map(predicate, self._items))
173
174    def take(self, n: int) -> FlatIterator[Item]:
175        """Take the first number of items until the number of items are yielded or
176        the end of the iterator is reached.
177
178        Example
179        -------
180        ```py
181        iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
182        print(iterator.take(2))
183        # <FlatIterator([GameMode.RAID, GameMode.STRIKE])>
184        ```
185
186        Parameters
187        ----------
188        n: `int`
189            The number of items to take.
190
191        Raises
192        ------
193        `StopIteration`
194            If no elements are left in the iterator.
195        """
196        return FlatIterator(itertools.islice(self._items, n))
197
198    def take_while(
199        self, predicate: collections.Callable[[Item], bool]
200    ) -> FlatIterator[Item]:
201        """Yields items from the iterator while predicate returns `True`.
202
203        Example
204        -------
205        ```py
206        iterator = FlatIterator([STEAM, XBOX, STADIA])
207        print(iterator.take_while(lambda platform: platform is not XBOX))
208        # <FlatIterator([STEAM])>
209        ```
210
211        Parameters
212        ----------
213        predicate: `collections.Callable[[Item], bool]`
214            The function to predicate each item in the iterator.
215
216        Raises
217        ------
218        `StopIteration`
219            If no elements are left in the iterator.
220        """
221        return FlatIterator(itertools.takewhile(predicate, self._items))
222
223    def drop_while(
224        self, predicate: collections.Callable[[Item], bool]
225    ) -> FlatIterator[Item]:
226        """Yields items from the iterator while predicate returns `False`.
227
228        Example
229        -------
230        ```py
231        iterator = FlatIterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
232        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
233        # <FlatIterator([DestinyMembership(name="Bob")])>
234        ```
235
236        Parameters
237        ----------
238        predicate: `collections.Callable[[Item], bool]`
239            The function to predicate each item in the iterator.
240
241        Raises
242        ------
243        `StopIteration`
244            If no elements are left in the iterator.
245        """
246        return FlatIterator(itertools.dropwhile(predicate, self._items))
247
248    def filter(
249        self, predicate: collections.Callable[[Item], bool]
250    ) -> FlatIterator[Item]:
251        """Filters the iterator to only yield items that match the predicate.
252
253        Example
254        -------
255        ```py
256        names = FlatIterator(["Jim", "Bob", "Mike", "Jess"])
257        print(names.filter(lambda n: n != "Jim"))
258        # <FlatIterator(["Bob", "Mike", "Jess"])>
259        ```
260        """
261        return FlatIterator(filter(predicate, self._items))
262
263    def skip(self, n: int) -> FlatIterator[Item]:
264        """Skips the first number of items in the iterator.
265
266        Example
267        -------
268        ```py
269        iterator = FlatIterator([STEAM, XBOX, STADIA])
270        print(iterator.skip(1))
271        # <FlatIterator([XBOX, STADIA])>
272        ```
273        """
274        return FlatIterator(itertools.islice(self._items, n, None))
275
276    def discard(
277        self, predicate: collections.Callable[[Item], bool]
278    ) -> FlatIterator[Item]:
279        """Discards all elements in the iterator for which the predicate function returns true.
280
281        Example
282        -------
283        ```py
284        iterator = FlatIterator(['A', 'B', 'C'])
285        print(iterator.discard(lambda x: x == 'B'))
286        # <FlatIterator(['A', 'C'])>
287        ```
288
289        Parameters
290        ----------
291        predicate: `collections.Callable[[Item], bool]`
292            The function to test each item in the iterator.
293
294        Raises
295        ------
296        `StopIteration`
297            If no elements are left in the iterator.
298        """
299        return FlatIterator(filter(lambda x: not predicate(x), self._items))
300
301    def zip(
302        self, other: FlatIterator[OtherItem]
303    ) -> FlatIterator[tuple[Item, OtherItem]]:
304        """Zips the iterator with another iterable.
305
306        Example
307        -------
308        ```py
309        iterator = FlatIterator([1, 3, 5])
310        other = FlatIterator([2, 4, 6])
311        for item, other_item in iterator.zip(other):
312            print(item, other_item)
313        # <FlatIterator([(1, 2), (3, 4), (5, 6)])>
314        ```
315
316        Parameters
317        ----------
318        other: `FlatIterator[OtherItem]`
319            The iterable to zip with.
320
321        Raises
322        ------
323        `StopIteration`
324            If no elements are left in the iterator.
325        """
326        return FlatIterator(zip(self._items, other))
327
328    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
329        """`True` if all items in the iterator match the predicate.
330
331        Example
332        -------
333        ```py
334        iterator = FlatIterator([1, 2, 3])
335        while iterator.all(lambda item: isinstance(item, int)):
336            print("Still all integers")
337            continue
338        # Still all integers
339        ```
340
341        Parameters
342        ----------
343        predicate: `collections.Callable[[Item], bool]`
344            The function to test each item in the iterator.
345
346        Raises
347        ------
348        `StopIteration`
349            If no elements are left in the iterator.
350        """
351        return all(predicate(item) for item in self)
352
353    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
354        """`True` if any items in the iterator match the predicate.
355
356        Example
357        -------
358        ```py
359        iterator = FlatIterator([1, 2, 3])
360        if iterator.any(lambda item: isinstance(item, int)):
361            print("At least one item is an int.")
362        # At least one item is an int.
363        ```
364
365        Parameters
366        ----------
367        predicate: `collections.Callable[[Item], bool]`
368            The function to test each item in the iterator.
369
370        Raises
371        ------
372        `StopIteration`
373            If no elements are left in the iterator.
374        """
375        return any(predicate(item) for item in self)
376
377    def sort(
378        self,
379        *,
380        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
381        reverse: bool = False,
382    ) -> FlatIterator[Item]:
383        """Sorts the iterator.
384
385        Example
386        -------
387        ```py
388        iterator = FlatIterator([3, 1, 6, 7])
389        print(iterator.sort(key=lambda item: item))
390        # <FlatIterator([1, 3, 6, 7])>
391        ```
392
393        Parameters
394        ----------
395        key: `collections.Callable[[Item], Any]`
396            The function to sort by.
397        reverse: `bool`
398            Whether to reverse the sort.
399
400        Raises
401        ------
402        `StopIteration`
403            If no elements are left in the iterator.
404        """
405        return FlatIterator(sorted(self._items, key=key, reverse=reverse))
406
407    def first(self) -> Item:
408        """Returns the first item in the iterator.
409
410        Example
411        -------
412        ```py
413        iterator = FlatIterator([3, 1, 6, 7])
414        print(iterator.first())
415        3
416        ```
417
418        Raises
419        ------
420        `StopIteration`
421            If no elements are left in the iterator.
422        """
423        return self.take(1).next()
424
425    def reversed(self) -> FlatIterator[Item]:
426        """Returns a new iterator that yields the items in the iterator in reverse order.
427
428        Example
429        -------
430        ```py
431        iterator = FlatIterator([3, 1, 6, 7])
432        print(iterator.reversed())
433        # <FlatIterator([7, 6, 1, 3])>
434        ```
435
436        Raises
437        ------
438        `StopIteration`
439            If no elements are left in the iterator.
440        """
441        return FlatIterator(reversed(self.collect()))
442
443    def count(self) -> int:
444        """Returns the number of items in the iterator.
445
446        Example
447        -------
448        ```py
449        iterator = FlatIterator([3, 1, 6, 7])
450        print(iterator.count())
451        4
452        ```
453        """
454        count = 0
455        for _ in self:
456            count += 1
457
458        return count
459
460    def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]:
461        """Returns a new iterator that yields all items from both iterators.
462
463        Example
464        -------
465        ```py
466        iterator = FlatIterator([1, 2, 3])
467        other = FlatIterator([4, 5, 6])
468        print(iterator.union(other))
469        # <FlatIterator([1, 2, 3, 4, 5, 6])>
470        ```
471
472        Parameters
473        ----------
474        other: `FlatIterator[Item]`
475            The iterable to union with.
476
477        Raises
478        ------
479        `StopIteration`
480            If no elements are left in the iterator.
481        """
482        return FlatIterator(itertools.chain(self._items, other))
483
484    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
485        """Calls the function on each item in the iterator.
486
487        Example
488        -------
489        ```py
490        iterator = FlatIterator([1, 2, 3])
491        iterator.for_each(lambda item: print(item))
492        # 1
493        # 2
494        # 3
495        ```
496
497        Parameters
498        ----------
499        func: `typeshed.Callable[[Item], None]`
500            The function to call on each item in the iterator.
501        """
502        for item in self:
503            func(item)
504
505    async def async_for_each(
506        self,
507        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
508    ) -> None:
509        """Calls the async function on each item in the iterator concurrently.
510
511        Example
512        -------
513        ```py
514        async def signup(username: str) -> None:
515            async with aiohttp.request('POST', '...') as r:
516                # Actual logic.
517                ...
518
519        async def main():
520            users = aiobungie.into_iter(["user_danny", "user_jojo"])
521            await users.async_for_each(lambda username: signup(username))
522        ```
523
524        Parameters
525        ----------
526        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
527            The async function to call on each item in the iterator.
528        """
529        await _helpers.awaits(*(func(item) for item in self))
530
531    def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]:
532        """Returns a new iterator that yields tuples of the index and item.
533
534        Example
535        -------
536        ```py
537        iterator = FlatIterator([1, 2, 3])
538        for index, item in iterator.enumerate():
539            print(index, item)
540        # 0 1
541        # 1 2
542        # 2 3
543        ```
544
545        Raises
546        ------
547        `StopIteration`
548            If no elements are left in the iterator.
549        """
550        return FlatIterator(enumerate(self._items, start=start))
551
552    def _ok(self) -> typing.NoReturn:
553        raise StopIteration("No more items in the iterator.") from None
554
555    def __getitem__(self, index: int) -> Item:
556        try:
557            return self.skip(index).first()
558        except IndexError:
559            self._ok()
560
561    def __or__(self, other: FlatIterator[Item]) -> FlatIterator[Item]:
562        return self.union(other)
563
564    # This is a never.
565    def __setitem__(self) -> typing.NoReturn:
566        raise TypeError(
567            f"{type(self).__name__} doesn't support item assignment."
568        ) from None
569
570    def __repr__(self) -> str:
571        return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>'
572
573    def __len__(self) -> int:
574        return self.count()
575
576    def __iter__(self) -> FlatIterator[Item]:
577        return self
578
579    def __next__(self) -> Item:
580        try:
581            item = next(self._items)
582        except StopIteration:
583            self._ok()
584
585        return item

A Flat, In-Memory iterator for sequenced based data.

Example
iterator = FlatIterator([1, 2, 3])

# Map the results.
for item in iterator.map(lambda item: item * 2):
    print(item)
# 2
# 4

# Indexing is also supported.
print(iterator[0])
# 1

# Normal iteration.
for item in iterator:
    print(item)
# 1
# 2
# 3

# Union two iterators.
iterator2 = FlatIterator([4, 5, 6])
final = iterator | iterator2
# <FlatIterator([1, 2, 3, 4, 5, 6])>
Parameters
  • items (collections.Iterable[Item]): The items to iterate over.
FlatIterator(items: collections.abc.Iterable[~Item])
84    def __init__(self, items: collections.Iterable[Item]) -> None:
85        self._items = iter(items)
def collect( self, casting: 'typing.Optional[_B]' = None) -> 'typing.Union[list[Item], list[_B]]':
 95    def collect(
 96        self, casting: typing.Optional[_B] = None
 97    ) -> typing.Union[list[Item], list[_B]]:
 98        """Collects all items in the iterator into a list and cast them into an object if provided.
 99
100        Example
101        -------
102        >>> iterator = FlatIterator([1, 2, 3])
103        >>> iterator.collect(casting=str)
104        ["1", "2", "3"]
105
106        Parameters
107        ----------
108        casting: `T | None`
109            The type to cast the items to. If `None` is provided, the items will be returned as is.
110
111        Raises
112        ------
113        `StopIteration`
114            If no elements are left in the iterator.
115        """
116        if casting is not None:
117            return typing.cast(list[_B], list(map(casting, self._items)))
118
119        return list(self._items)

Collects all items in the iterator into a list and cast them into an object if provided.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.collect(casting=str)
["1", "2", "3"]
Parameters
  • casting (T | None): The type to cast the items to. If None is provided, the items will be returned as is.
Raises
  • StopIteration: If no elements are left in the iterator.
def next(self) -> ~Item:
121    def next(self) -> Item:
122        """Returns the next item in the iterator.
123
124        Example
125        -------
126        ```py
127        iterator = FlatIterator(["1", "2", "3"])
128        item = iterator.next()
129        assert item == "1"
130        item = iterator.next()
131        assert item == "2"
132        ```
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        try:
140            return self.__next__()
141        except StopIteration:
142            self._ok()

Returns the next item in the iterator.

Example
iterator = FlatIterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
  • StopIteration: If no elements are left in the iterator.
def map( self, predicate: 'collections.Callable[[Item], OtherItem]') -> 'FlatIterator[OtherItem]':
144    def map(
145        self, predicate: collections.Callable[[Item], OtherItem]
146    ) -> FlatIterator[OtherItem]:
147        """Maps each item in the iterator to its predicated value.
148
149        Example
150        -------
151        ```py
152        iterator = FlatIterator(["1", "2", "3"]).map(lambda value: int(value))
153        print(iterator)
154        # <FlatIterator([1, 2, 3])>
155        ```
156
157        Parameters
158        ----------
159        predicate: `collections.Callable[[Item], OtherItem]`
160            The function to map each item in the iterator to its predicated value.
161
162        Returns
163        -------
164        `FlatIterator[OtherItem]`
165            The mapped iterator.
166
167        Raises
168        ------
169        `StopIteration`
170            If no elements are left in the iterator.
171        """
172        return FlatIterator(map(predicate, self._items))

Maps each item in the iterator to its predicated value.

Example
iterator = FlatIterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <FlatIterator([1, 2, 3])>
Parameters
  • predicate (collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
  • FlatIterator[OtherItem]: The mapped iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def take(self, n: int) -> aiobungie.FlatIterator[~Item]:
174    def take(self, n: int) -> FlatIterator[Item]:
175        """Take the first number of items until the number of items are yielded or
176        the end of the iterator is reached.
177
178        Example
179        -------
180        ```py
181        iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
182        print(iterator.take(2))
183        # <FlatIterator([GameMode.RAID, GameMode.STRIKE])>
184        ```
185
186        Parameters
187        ----------
188        n: `int`
189            The number of items to take.
190
191        Raises
192        ------
193        `StopIteration`
194            If no elements are left in the iterator.
195        """
196        return FlatIterator(itertools.islice(self._items, n))

Take the first number of items until the number of items are yielded or the end of the iterator is reached.

Example
iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <FlatIterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
  • n (int): The number of items to take.
Raises
  • StopIteration: If no elements are left in the iterator.
def take_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
198    def take_while(
199        self, predicate: collections.Callable[[Item], bool]
200    ) -> FlatIterator[Item]:
201        """Yields items from the iterator while predicate returns `True`.
202
203        Example
204        -------
205        ```py
206        iterator = FlatIterator([STEAM, XBOX, STADIA])
207        print(iterator.take_while(lambda platform: platform is not XBOX))
208        # <FlatIterator([STEAM])>
209        ```
210
211        Parameters
212        ----------
213        predicate: `collections.Callable[[Item], bool]`
214            The function to predicate each item in the iterator.
215
216        Raises
217        ------
218        `StopIteration`
219            If no elements are left in the iterator.
220        """
221        return FlatIterator(itertools.takewhile(predicate, self._items))

Yields items from the iterator while predicate returns True.

Example
iterator = FlatIterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <FlatIterator([STEAM])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def drop_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
223    def drop_while(
224        self, predicate: collections.Callable[[Item], bool]
225    ) -> FlatIterator[Item]:
226        """Yields items from the iterator while predicate returns `False`.
227
228        Example
229        -------
230        ```py
231        iterator = FlatIterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
232        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
233        # <FlatIterator([DestinyMembership(name="Bob")])>
234        ```
235
236        Parameters
237        ----------
238        predicate: `collections.Callable[[Item], bool]`
239            The function to predicate each item in the iterator.
240
241        Raises
242        ------
243        `StopIteration`
244            If no elements are left in the iterator.
245        """
246        return FlatIterator(itertools.dropwhile(predicate, self._items))

Yields items from the iterator while predicate returns False.

Example
iterator = FlatIterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <FlatIterator([DestinyMembership(name="Bob")])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def filter( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
248    def filter(
249        self, predicate: collections.Callable[[Item], bool]
250    ) -> FlatIterator[Item]:
251        """Filters the iterator to only yield items that match the predicate.
252
253        Example
254        -------
255        ```py
256        names = FlatIterator(["Jim", "Bob", "Mike", "Jess"])
257        print(names.filter(lambda n: n != "Jim"))
258        # <FlatIterator(["Bob", "Mike", "Jess"])>
259        ```
260        """
261        return FlatIterator(filter(predicate, self._items))

Filters the iterator to only yield items that match the predicate.

Example
names = FlatIterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <FlatIterator(["Bob", "Mike", "Jess"])>
def skip(self, n: int) -> aiobungie.FlatIterator[~Item]:
263    def skip(self, n: int) -> FlatIterator[Item]:
264        """Skips the first number of items in the iterator.
265
266        Example
267        -------
268        ```py
269        iterator = FlatIterator([STEAM, XBOX, STADIA])
270        print(iterator.skip(1))
271        # <FlatIterator([XBOX, STADIA])>
272        ```
273        """
274        return FlatIterator(itertools.islice(self._items, n, None))

Skips the first number of items in the iterator.

Example
iterator = FlatIterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <FlatIterator([XBOX, STADIA])>
def discard( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
276    def discard(
277        self, predicate: collections.Callable[[Item], bool]
278    ) -> FlatIterator[Item]:
279        """Discards all elements in the iterator for which the predicate function returns true.
280
281        Example
282        -------
283        ```py
284        iterator = FlatIterator(['A', 'B', 'C'])
285        print(iterator.discard(lambda x: x == 'B'))
286        # <FlatIterator(['A', 'C'])>
287        ```
288
289        Parameters
290        ----------
291        predicate: `collections.Callable[[Item], bool]`
292            The function to test each item in the iterator.
293
294        Raises
295        ------
296        `StopIteration`
297            If no elements are left in the iterator.
298        """
299        return FlatIterator(filter(lambda x: not predicate(x), self._items))

Discards all elements in the iterator for which the predicate function returns true.

Example
iterator = FlatIterator(['A', 'B', 'C'])
print(iterator.discard(lambda x: x == 'B'))
# <FlatIterator(['A', 'C'])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def zip( self, other: 'FlatIterator[OtherItem]') -> 'FlatIterator[tuple[Item, OtherItem]]':
301    def zip(
302        self, other: FlatIterator[OtherItem]
303    ) -> FlatIterator[tuple[Item, OtherItem]]:
304        """Zips the iterator with another iterable.
305
306        Example
307        -------
308        ```py
309        iterator = FlatIterator([1, 3, 5])
310        other = FlatIterator([2, 4, 6])
311        for item, other_item in iterator.zip(other):
312            print(item, other_item)
313        # <FlatIterator([(1, 2), (3, 4), (5, 6)])>
314        ```
315
316        Parameters
317        ----------
318        other: `FlatIterator[OtherItem]`
319            The iterable to zip with.
320
321        Raises
322        ------
323        `StopIteration`
324            If no elements are left in the iterator.
325        """
326        return FlatIterator(zip(self._items, other))

Zips the iterator with another iterable.

Example
iterator = FlatIterator([1, 3, 5])
other = FlatIterator([2, 4, 6])
for item, other_item in iterator.zip(other):
    print(item, other_item)
# <FlatIterator([(1, 2), (3, 4), (5, 6)])>
Parameters
  • other (FlatIterator[OtherItem]): The iterable to zip with.
Raises
  • StopIteration: If no elements are left in the iterator.
def all(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
328    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
329        """`True` if all items in the iterator match the predicate.
330
331        Example
332        -------
333        ```py
334        iterator = FlatIterator([1, 2, 3])
335        while iterator.all(lambda item: isinstance(item, int)):
336            print("Still all integers")
337            continue
338        # Still all integers
339        ```
340
341        Parameters
342        ----------
343        predicate: `collections.Callable[[Item], bool]`
344            The function to test each item in the iterator.
345
346        Raises
347        ------
348        `StopIteration`
349            If no elements are left in the iterator.
350        """
351        return all(predicate(item) for item in self)

True if all items in the iterator match the predicate.

Example
iterator = FlatIterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
    print("Still all integers")
    continue
# Still all integers
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def any(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
353    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
354        """`True` if any items in the iterator match the predicate.
355
356        Example
357        -------
358        ```py
359        iterator = FlatIterator([1, 2, 3])
360        if iterator.any(lambda item: isinstance(item, int)):
361            print("At least one item is an int.")
362        # At least one item is an int.
363        ```
364
365        Parameters
366        ----------
367        predicate: `collections.Callable[[Item], bool]`
368            The function to test each item in the iterator.
369
370        Raises
371        ------
372        `StopIteration`
373            If no elements are left in the iterator.
374        """
375        return any(predicate(item) for item in self)

True if any items in the iterator match the predicate.

Example
iterator = FlatIterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
    print("At least one item is an int.")
# At least one item is an int.
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def sort( self, *, key: 'collections.Callable[[Item], typeshed.SupportsRichComparison]', reverse: bool = False) -> aiobungie.FlatIterator[~Item]:
377    def sort(
378        self,
379        *,
380        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
381        reverse: bool = False,
382    ) -> FlatIterator[Item]:
383        """Sorts the iterator.
384
385        Example
386        -------
387        ```py
388        iterator = FlatIterator([3, 1, 6, 7])
389        print(iterator.sort(key=lambda item: item))
390        # <FlatIterator([1, 3, 6, 7])>
391        ```
392
393        Parameters
394        ----------
395        key: `collections.Callable[[Item], Any]`
396            The function to sort by.
397        reverse: `bool`
398            Whether to reverse the sort.
399
400        Raises
401        ------
402        `StopIteration`
403            If no elements are left in the iterator.
404        """
405        return FlatIterator(sorted(self._items, key=key, reverse=reverse))

Sorts the iterator.

Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <FlatIterator([1, 3, 6, 7])>
Parameters
  • key (collections.Callable[[Item], Any]): The function to sort by.
  • reverse (bool): Whether to reverse the sort.
Raises
  • StopIteration: If no elements are left in the iterator.
def first(self) -> ~Item:
407    def first(self) -> Item:
408        """Returns the first item in the iterator.
409
410        Example
411        -------
412        ```py
413        iterator = FlatIterator([3, 1, 6, 7])
414        print(iterator.first())
415        3
416        ```
417
418        Raises
419        ------
420        `StopIteration`
421            If no elements are left in the iterator.
422        """
423        return self.take(1).next()

Returns the first item in the iterator.

Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
  • StopIteration: If no elements are left in the iterator.
def reversed(self) -> aiobungie.FlatIterator[~Item]:
425    def reversed(self) -> FlatIterator[Item]:
426        """Returns a new iterator that yields the items in the iterator in reverse order.
427
428        Example
429        -------
430        ```py
431        iterator = FlatIterator([3, 1, 6, 7])
432        print(iterator.reversed())
433        # <FlatIterator([7, 6, 1, 3])>
434        ```
435
436        Raises
437        ------
438        `StopIteration`
439            If no elements are left in the iterator.
440        """
441        return FlatIterator(reversed(self.collect()))

Returns a new iterator that yields the items in the iterator in reverse order.

Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.reversed())
# <FlatIterator([7, 6, 1, 3])>
Raises
  • StopIteration: If no elements are left in the iterator.
def count(self) -> int:
443    def count(self) -> int:
444        """Returns the number of items in the iterator.
445
446        Example
447        -------
448        ```py
449        iterator = FlatIterator([3, 1, 6, 7])
450        print(iterator.count())
451        4
452        ```
453        """
454        count = 0
455        for _ in self:
456            count += 1
457
458        return count

Returns the number of items in the iterator.

Example
iterator = FlatIterator([3, 1, 6, 7])
print(iterator.count())
4
def union( self, other: aiobungie.FlatIterator[~Item]) -> aiobungie.FlatIterator[~Item]:
460    def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]:
461        """Returns a new iterator that yields all items from both iterators.
462
463        Example
464        -------
465        ```py
466        iterator = FlatIterator([1, 2, 3])
467        other = FlatIterator([4, 5, 6])
468        print(iterator.union(other))
469        # <FlatIterator([1, 2, 3, 4, 5, 6])>
470        ```
471
472        Parameters
473        ----------
474        other: `FlatIterator[Item]`
475            The iterable to union with.
476
477        Raises
478        ------
479        `StopIteration`
480            If no elements are left in the iterator.
481        """
482        return FlatIterator(itertools.chain(self._items, other))

Returns a new iterator that yields all items from both iterators.

Example
iterator = FlatIterator([1, 2, 3])
other = FlatIterator([4, 5, 6])
print(iterator.union(other))
# <FlatIterator([1, 2, 3, 4, 5, 6])>
Parameters
  • other (FlatIterator[Item]): The iterable to union with.
Raises
  • StopIteration: If no elements are left in the iterator.
def for_each(self, func: collections.abc.Callable[[~Item], typing.Any]) -> None:
484    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
485        """Calls the function on each item in the iterator.
486
487        Example
488        -------
489        ```py
490        iterator = FlatIterator([1, 2, 3])
491        iterator.for_each(lambda item: print(item))
492        # 1
493        # 2
494        # 3
495        ```
496
497        Parameters
498        ----------
499        func: `typeshed.Callable[[Item], None]`
500            The function to call on each item in the iterator.
501        """
502        for item in self:
503            func(item)

Calls the function on each item in the iterator.

Example
iterator = FlatIterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
  • func (typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
async def async_for_each( self, func: collections.abc.Callable[[~Item], collections.abc.Coroutine[None, None, None]]) -> None:
505    async def async_for_each(
506        self,
507        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
508    ) -> None:
509        """Calls the async function on each item in the iterator concurrently.
510
511        Example
512        -------
513        ```py
514        async def signup(username: str) -> None:
515            async with aiohttp.request('POST', '...') as r:
516                # Actual logic.
517                ...
518
519        async def main():
520            users = aiobungie.into_iter(["user_danny", "user_jojo"])
521            await users.async_for_each(lambda username: signup(username))
522        ```
523
524        Parameters
525        ----------
526        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
527            The async function to call on each item in the iterator.
528        """
529        await _helpers.awaits(*(func(item) for item in self))

Calls the async function on each item in the iterator concurrently.

Example
async def signup(username: str) -> None:
    async with aiohttp.request('POST', '...') as r:
        # Actual logic.
        ...

async def main():
    users = aiobungie.into_iter(["user_danny", "user_jojo"])
    await users.async_for_each(lambda username: signup(username))
Parameters
  • func (collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
def enumerate( self, *, start: int = 0) -> aiobungie.FlatIterator[tuple[int, ~Item]]:
531    def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]:
532        """Returns a new iterator that yields tuples of the index and item.
533
534        Example
535        -------
536        ```py
537        iterator = FlatIterator([1, 2, 3])
538        for index, item in iterator.enumerate():
539            print(index, item)
540        # 0 1
541        # 1 2
542        # 2 3
543        ```
544
545        Raises
546        ------
547        `StopIteration`
548            If no elements are left in the iterator.
549        """
550        return FlatIterator(enumerate(self._items, start=start))

Returns a new iterator that yields tuples of the index and item.

Example
iterator = FlatIterator([1, 2, 3])
for index, item in iterator.enumerate():
    print(index, item)
# 0 1
# 1 2
# 2 3
Raises
  • StopIteration: If no elements are left in the iterator.
@attrs.define(auto_exc=True)
class Forbidden(aiobungie.HTTPException):
120@attrs.define(auto_exc=True)
121class Forbidden(HTTPException):
122    """Exception that's raised for when status code 403 occurs."""
123
124    http_status: http.HTTPStatus = attrs.field(
125        default=http.HTTPStatus.FORBIDDEN, init=False
126    )

Exception that's raised for when status code 403 occurs.

Forbidden( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Forbidden.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class GameMode(builtins.int, aiobungie.Enum):
274@typing.final
275class GameMode(int, Enum):
276    """An Enum for all available gamemodes in Destiny 2."""
277
278    NONE = 0
279    STORY = 2
280    STRIKE = 3
281    RAID = 4
282    ALLPVP = 5
283    PATROL = 6
284    ALLPVE = 7
285    RESERVED9 = 9
286    CONTROL = 10
287    RESERVED11 = 11
288    CLASH = 12
289    RESERVED13 = 13
290    CRIMSONDOUBLES = 15
291    NIGHTFALL = 16
292    HEROICNIGHTFALL = 17
293    ALLSTRIKES = 18
294    IRONBANNER = 19
295    RESERVED20 = 20
296    RESERVED21 = 21
297    RESERVED22 = 22
298    RESERVED24 = 24
299    ALLMAYHEM = 25
300    RESERVED26 = 26
301    RESERVED27 = 27
302    RESERVED28 = 28
303    RESERVED29 = 29
304    RESERVED30 = 30
305    SUPREMACY = 31
306    PRIVATEMATCHESALL = 32
307    SURVIVAL = 37
308    COUNTDOWN = 38
309    TRIALSOFTHENINE = 39
310    SOCIAL = 40
311    TRIALSCOUNTDOWN = 41
312    TRIALSSURVIVAL = 42
313    IRONBANNERCONTROL = 43
314    IRONBANNERCLASH = 44
315    IRONBANNERSUPREMACY = 45
316    SCOREDNIGHTFALL = 46
317    SCOREDHEROICNIGHTFALL = 47
318    RUMBLE = 48
319    ALLDOUBLES = 49
320    DOUBLES = 50
321    PRIVATEMATCHESCLASH = 51
322    PRIVATEMATCHESCONTROL = 52
323    PRIVATEMATCHESSUPREMACY = 53
324    PRIVATEMATCHESCOUNTDOWN = 54
325    PRIVATEMATCHESSURVIVAL = 55
326    PRIVATEMATCHESMAYHEM = 56
327    PRIVATEMATCHESRUMBLE = 57
328    HEROICADVENTURE = 58
329    SHOWDOWN = 59
330    LOCKDOWN = 60
331    SCORCHED = 61
332    SCORCHEDTEAM = 62
333    GAMBIT = 63
334    ALLPVECOMPETITIVE = 64
335    BREAKTHROUGH = 65
336    BLACKARMORYRUN = 66
337    SALVAGE = 67
338    IRONBANNERSALVAGE = 68
339    PVPCOMPETITIVE = 69
340    PVPQUICKPLAY = 70
341    CLASHQUICKPLAY = 71
342    CLASHCOMPETITIVE = 72
343    CONTROLQUICKPLAY = 73
344    CONTROLCOMPETITIVE = 74
345    GAMBITPRIME = 75
346    RECKONING = 76
347    MENAGERIE = 77
348    VEXOFFENSIVE = 78
349    NIGHTMAREHUNT = 79
350    ELIMINATION = 80
351    MOMENTUM = 81
352    DUNGEON = 82
353    SUNDIAL = 83
354    TRIALS_OF_OSIRIS = 84
355    DARES = 85
356    OFFENSIVE = 86
357    LOSTSECTOR = 87
358    RIFT = 88
359    ZONECONTROL = 89
360    IRONBANNERRIFT = 90

An Enum for all available gamemodes in Destiny 2.

NONE = <GameMode.NONE: 0>
STORY = <GameMode.STORY: 2>
STRIKE = <GameMode.STRIKE: 3>
RAID = <GameMode.RAID: 4>
ALLPVP = <GameMode.ALLPVP: 5>
PATROL = <GameMode.PATROL: 6>
ALLPVE = <GameMode.ALLPVE: 7>
RESERVED9 = <GameMode.RESERVED9: 9>
CONTROL = <GameMode.CONTROL: 10>
RESERVED11 = <GameMode.RESERVED11: 11>
CLASH = <GameMode.CLASH: 12>
RESERVED13 = <GameMode.RESERVED13: 13>
CRIMSONDOUBLES = <GameMode.CRIMSONDOUBLES: 15>
NIGHTFALL = <GameMode.NIGHTFALL: 16>
HEROICNIGHTFALL = <GameMode.HEROICNIGHTFALL: 17>
ALLSTRIKES = <GameMode.ALLSTRIKES: 18>
IRONBANNER = <GameMode.IRONBANNER: 19>
RESERVED20 = <GameMode.RESERVED20: 20>
RESERVED21 = <GameMode.RESERVED21: 21>
RESERVED22 = <GameMode.RESERVED22: 22>
RESERVED24 = <GameMode.RESERVED24: 24>
ALLMAYHEM = <GameMode.ALLMAYHEM: 25>
RESERVED26 = <GameMode.RESERVED26: 26>
RESERVED27 = <GameMode.RESERVED27: 27>
RESERVED28 = <GameMode.RESERVED28: 28>
RESERVED29 = <GameMode.RESERVED29: 29>
RESERVED30 = <GameMode.RESERVED30: 30>
SUPREMACY = <GameMode.SUPREMACY: 31>
PRIVATEMATCHESALL = <GameMode.PRIVATEMATCHESALL: 32>
SURVIVAL = <GameMode.SURVIVAL: 37>
COUNTDOWN = <GameMode.COUNTDOWN: 38>
TRIALSOFTHENINE = <GameMode.TRIALSOFTHENINE: 39>
SOCIAL = <GameMode.SOCIAL: 40>
TRIALSCOUNTDOWN = <GameMode.TRIALSCOUNTDOWN: 41>
TRIALSSURVIVAL = <GameMode.TRIALSSURVIVAL: 42>
IRONBANNERCONTROL = <GameMode.IRONBANNERCONTROL: 43>
IRONBANNERCLASH = <GameMode.IRONBANNERCLASH: 44>
IRONBANNERSUPREMACY = <GameMode.IRONBANNERSUPREMACY: 45>
SCOREDNIGHTFALL = <GameMode.SCOREDNIGHTFALL: 46>
SCOREDHEROICNIGHTFALL = <GameMode.SCOREDHEROICNIGHTFALL: 47>
RUMBLE = <GameMode.RUMBLE: 48>
ALLDOUBLES = <GameMode.ALLDOUBLES: 49>
DOUBLES = <GameMode.DOUBLES: 50>
PRIVATEMATCHESCLASH = <GameMode.PRIVATEMATCHESCLASH: 51>
PRIVATEMATCHESCONTROL = <GameMode.PRIVATEMATCHESCONTROL: 52>
PRIVATEMATCHESSUPREMACY = <GameMode.PRIVATEMATCHESSUPREMACY: 53>
PRIVATEMATCHESCOUNTDOWN = <GameMode.PRIVATEMATCHESCOUNTDOWN: 54>
PRIVATEMATCHESSURVIVAL = <GameMode.PRIVATEMATCHESSURVIVAL: 55>
PRIVATEMATCHESMAYHEM = <GameMode.PRIVATEMATCHESMAYHEM: 56>
PRIVATEMATCHESRUMBLE = <GameMode.PRIVATEMATCHESRUMBLE: 57>
HEROICADVENTURE = <GameMode.HEROICADVENTURE: 58>
SHOWDOWN = <GameMode.SHOWDOWN: 59>
LOCKDOWN = <GameMode.LOCKDOWN: 60>
SCORCHED = <GameMode.SCORCHED: 61>
SCORCHEDTEAM = <GameMode.SCORCHEDTEAM: 62>
GAMBIT = <GameMode.GAMBIT: 63>
ALLPVECOMPETITIVE = <GameMode.ALLPVECOMPETITIVE: 64>
BREAKTHROUGH = <GameMode.BREAKTHROUGH: 65>
BLACKARMORYRUN = <GameMode.BLACKARMORYRUN: 66>
SALVAGE = <GameMode.SALVAGE: 67>
IRONBANNERSALVAGE = <GameMode.IRONBANNERSALVAGE: 68>
PVPCOMPETITIVE = <GameMode.PVPCOMPETITIVE: 69>
PVPQUICKPLAY = <GameMode.PVPQUICKPLAY: 70>
CLASHQUICKPLAY = <GameMode.CLASHQUICKPLAY: 71>
CLASHCOMPETITIVE = <GameMode.CLASHCOMPETITIVE: 72>
CONTROLQUICKPLAY = <GameMode.CONTROLQUICKPLAY: 73>
CONTROLCOMPETITIVE = <GameMode.CONTROLCOMPETITIVE: 74>
GAMBITPRIME = <GameMode.GAMBITPRIME: 75>
RECKONING = <GameMode.RECKONING: 76>
MENAGERIE = <GameMode.MENAGERIE: 77>
VEXOFFENSIVE = <GameMode.VEXOFFENSIVE: 78>
NIGHTMAREHUNT = <GameMode.NIGHTMAREHUNT: 79>
ELIMINATION = <GameMode.ELIMINATION: 80>
MOMENTUM = <GameMode.MOMENTUM: 81>
DUNGEON = <GameMode.DUNGEON: 82>
SUNDIAL = <GameMode.SUNDIAL: 83>
TRIALS_OF_OSIRIS = <GameMode.TRIALS_OF_OSIRIS: 84>
DARES = <GameMode.DARES: 85>
OFFENSIVE = <GameMode.OFFENSIVE: 86>
LOSTSECTOR = <GameMode.LOSTSECTOR: 87>
RIFT = <GameMode.RIFT: 88>
ZONECONTROL = <GameMode.ZONECONTROL: 89>
IRONBANNERRIFT = <GameMode.IRONBANNERRIFT: 90>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GatingScope(builtins.int, aiobungie.Enum):
58@typing.final
59class GatingScope(int, enums.Enum):
60    """An enum represents restrictive type of gating that is being performed by an entity.
61
62    This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity
63    applies to everyone equally, or to their specific Profile or Character states.
64    """
65
66    NONE = 0
67    GLOBAL = 1
68    CLAN = 2
69    PROFILE = 3
70    CHARACTER = 4
71    ITEM = 5
72    ASSUMED_WORST_CASE = 6

An enum represents restrictive type of gating that is being performed by an entity.

This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.

NONE = <GatingScope.NONE: 0>
GLOBAL = <GatingScope.GLOBAL: 1>
CLAN = <GatingScope.CLAN: 2>
PROFILE = <GatingScope.PROFILE: 3>
CHARACTER = <GatingScope.CHARACTER: 4>
ITEM = <GatingScope.ITEM: 5>
ASSUMED_WORST_CASE = <GatingScope.ASSUMED_WORST_CASE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Gender(builtins.int, aiobungie.Enum):
487@typing.final
488class Gender(int, Enum):
489    """An Enum for Destiny Genders."""
490
491    MALE = 0
492    FEMALE = 1
493    UNKNOWN = 2

An Enum for Destiny Genders.

MALE = <Gender.MALE: 0>
FEMALE = <Gender.FEMALE: 1>
UNKNOWN = <Gender.UNKNOWN: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GroupType(builtins.int, aiobungie.Enum):
656@typing.final
657class GroupType(int, Enum):
658    """An enums for the known bungie group types."""
659
660    GENERAL = 0
661    CLAN = 1

An enums for the known bungie group types.

GENERAL = <GroupType.GENERAL: 0>
CLAN = <GroupType.CLAN: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class HTTPError(aiobungie.AiobungieError):
62@attrs.define(auto_exc=True)
63class HTTPError(AiobungieError):
64    """Exception base used for HTTP request errors."""
65
66    message: str
67    """The error message."""
68
69    http_status: http.HTTPStatus
70    """The response status."""

Exception base used for HTTP request errors.

HTTPError(message: str, http_status: http.HTTPStatus)
2def __init__(self, message, http_status):
3    self.message = message
4    self.http_status = http_status
5    BaseException.__init__(self, self.message,self.http_status)

Method generated by attrs for class HTTPError.

message: str

The error message.

http_status: http.HTTPStatus

The response status.

Inherited Members
builtins.BaseException
with_traceback
args
@attrs.define(auto_exc=True, kw_only=True)
class HTTPException(aiobungie.HTTPError):
 73@attrs.define(auto_exc=True, kw_only=True)
 74class HTTPException(HTTPError):
 75    """Exception base internally used for an HTTP request response errors."""
 76
 77    error_code: int
 78    """The returned Bungie error status code."""
 79
 80    http_status: http.HTTPStatus
 81    """The request response http status."""
 82
 83    throttle_seconds: int
 84    """The Bungie response throttle seconds."""
 85
 86    url: typing.Optional[typedefs.StrOrURL]
 87    """The URL/endpoint caused this error."""
 88
 89    body: typing.Any
 90    """The response body."""
 91
 92    headers: multidict.CIMultiDictProxy[str]
 93    """The response headers."""
 94
 95    message: str
 96    """A Bungie human readable message describes the cause of the error."""
 97
 98    error_status: str
 99    """A Bungie short error status describes the cause of the error."""
100
101    message_data: dict[str, str]
102    """A dict of string key, value that includes each cause of the error
103    to a message describes information about that error.
104    """
105
106    def __str__(self) -> str:
107        if self.message:
108            message_body = self.message
109
110        if self.error_status:
111            error_status_body = self.error_status
112
113        return (
114            f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: "
115            f"Error status: {error_status_body}, Error message: {message_body} from {self.url} "
116            f"{str(self.body)}"
117        )

Exception base internally used for an HTTP request response errors.

HTTPException( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class HTTPException.

error_code: int

The returned Bungie error status code.

http_status: http.HTTPStatus

The request response http status.

throttle_seconds: int

The Bungie response throttle seconds.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

message: str

A Bungie human readable message describes the cause of the error.

error_status: str

A Bungie short error status describes the cause of the error.

message_data: dict[str, str]

A dict of string key, value that includes each cause of the error to a message describes information about that error.

Inherited Members
builtins.BaseException
with_traceback
args
class Image:
 72class Image:
 73    """Representation of an image/avatar/picture at Bungie.
 74
 75    Example
 76    -------
 77    ```py
 78    from aiobungie import Image
 79    img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
 80    print(img)
 81    # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
 82
 83    # Stream the image.
 84    async for chunk in img:
 85        # Byte chunks of the image.
 86        print(chunk)
 87
 88    # Save the image to a file.
 89    await img.save("file_name", "/my/path/to/save/to", "jpeg")
 90    ```
 91
 92    Parameters
 93    ----------
 94    path : `str | None`
 95        The path to the image. If `None`, the default missing image path will be used.
 96    """
 97
 98    __slots__ = ("_path",)
 99
100    def __init__(self, path: typing.Optional[str] = None) -> None:
101        self._path = path
102
103    @property
104    def is_missing(self) -> bool:
105        return not self._path
106
107    @property
108    def url(self) -> str:
109        """The URL to the image."""
110        return self.create_url()
111
112    @staticmethod
113    def missing_path() -> str:
114        """Returns the path to the missing Bungie image."""
115        return "img/misc/missing_icon_d2.png"
116
117    def create_url(self) -> str:
118        """Creates a full URL to the image path.
119
120        Returns
121        -------
122        str
123            The URL to the image.
124        """
125        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
126
127    async def save(
128        self,
129        file_name: str,
130        path: typing.Union[pathlib.Path, str],
131        /,
132        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
133    ) -> None:
134        """Saves the image to a file.
135
136        Parameters
137        ----------
138        file_name : `str`
139            A name for the file to save the image to.
140        path : `pathlib.Path | str`
141            A path tp save the image to.
142
143        Other Parameters
144        ----------------
145        mime_type : `MimeType | str`
146            Optional MIME type of the image.
147
148        Raises
149        ------
150        `FileNotFoundError`
151            If the path provided does not exist.
152        `RuntimeError`
153            If the image could not be saved.
154        `PermissionError`
155            If the path provided is not writable or does not have write permissions.
156        """
157        if isinstance(path, pathlib.Path) and not path.exists():
158            raise FileNotFoundError(f"File does not exist: {path!r}")
159
160        if self.is_missing:
161            return
162
163        mimetype = mime_type or MimeType.PNG
164        path = pathlib.Path(path)
165
166        loop = helpers.get_or_make_loop()
167        pool = concurrent.futures.ThreadPoolExecutor()
168
169        try:
170            with pool:
171                await loop.run_in_executor(
172                    pool, _write, path, file_name, mimetype, await self.read()
173                )
174                _LOGGER.info("Saved image to %s", file_name)
175
176        except asyncio.CancelledError:
177            pass
178
179        except Exception as err:
180            raise RuntimeError("Encountered an error while saving image.") from err
181
182    async def read(self) -> bytes:
183        """Read this image bytes.
184
185        Returns
186        -------
187        `bytes`
188            The bytes of this image.
189        """
190        client_session = aiohttp.ClientSession()
191
192        try:
193            await client_session.__aenter__()
194            response = await client_session.get(self.create_url())
195
196            if 300 >= response.status >= 200:
197                reader = await response.read()
198
199        except Exception as exc:
200            raise RuntimeError(f"Failed to read image: {exc}") from None
201        finally:
202            await client_session.__aexit__(None, None, None)
203        return reader
204
205    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
206        """Iterates over the image bytes lazily.
207
208        Example
209        -------
210        import aiobungie
211
212        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
213        async for chunk in resource.iter():
214            print(chunk)
215
216        Returns
217        -------
218        `collections.AsyncGenerator[bytes, None]`
219            An async generator of the image bytes.
220        """
221
222        async for chunk in self:
223            yield chunk
224
225    def __repr__(self) -> str:
226        return f"Image(url={self.create_url()})"
227
228    def __str__(self) -> str:
229        return self.create_url()
230
231    def __aiter__(self) -> Image:
232        return self
233
234    async def __anext__(self) -> bytes:
235        return await self.read()
236
237    def __await__(self) -> collections.Generator[None, None, bytes]:
238        return self.__anext__().__await__()

Representation of an image/avatar/picture at Bungie.

Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg

# Stream the image.
async for chunk in img:
    # Byte chunks of the image.
    print(chunk)

# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
  • path (str | None): The path to the image. If None, the default missing image path will be used.
Image(path: Optional[str] = None)
100    def __init__(self, path: typing.Optional[str] = None) -> None:
101        self._path = path
is_missing: bool
url: str

The URL to the image.

@staticmethod
def missing_path() -> str:
112    @staticmethod
113    def missing_path() -> str:
114        """Returns the path to the missing Bungie image."""
115        return "img/misc/missing_icon_d2.png"

Returns the path to the missing Bungie image.

def create_url(self) -> str:
117    def create_url(self) -> str:
118        """Creates a full URL to the image path.
119
120        Returns
121        -------
122        str
123            The URL to the image.
124        """
125        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"

Creates a full URL to the image path.

Returns
  • str: The URL to the image.
async def save( self, file_name: str, path: Union[pathlib.Path, str], /, mime_type: Union[aiobungie.internal.assets.MimeType, str, NoneType] = None) -> None:
127    async def save(
128        self,
129        file_name: str,
130        path: typing.Union[pathlib.Path, str],
131        /,
132        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
133    ) -> None:
134        """Saves the image to a file.
135
136        Parameters
137        ----------
138        file_name : `str`
139            A name for the file to save the image to.
140        path : `pathlib.Path | str`
141            A path tp save the image to.
142
143        Other Parameters
144        ----------------
145        mime_type : `MimeType | str`
146            Optional MIME type of the image.
147
148        Raises
149        ------
150        `FileNotFoundError`
151            If the path provided does not exist.
152        `RuntimeError`
153            If the image could not be saved.
154        `PermissionError`
155            If the path provided is not writable or does not have write permissions.
156        """
157        if isinstance(path, pathlib.Path) and not path.exists():
158            raise FileNotFoundError(f"File does not exist: {path!r}")
159
160        if self.is_missing:
161            return
162
163        mimetype = mime_type or MimeType.PNG
164        path = pathlib.Path(path)
165
166        loop = helpers.get_or_make_loop()
167        pool = concurrent.futures.ThreadPoolExecutor()
168
169        try:
170            with pool:
171                await loop.run_in_executor(
172                    pool, _write, path, file_name, mimetype, await self.read()
173                )
174                _LOGGER.info("Saved image to %s", file_name)
175
176        except asyncio.CancelledError:
177            pass
178
179        except Exception as err:
180            raise RuntimeError("Encountered an error while saving image.") from err

Saves the image to a file.

Parameters
  • file_name (str): A name for the file to save the image to.
  • path (pathlib.Path | str): A path tp save the image to.
Other Parameters
  • mime_type (MimeType | str): Optional MIME type of the image.
Raises
  • FileNotFoundError: If the path provided does not exist.
  • RuntimeError: If the image could not be saved.
  • PermissionError: If the path provided is not writable or does not have write permissions.
async def read(self) -> bytes:
182    async def read(self) -> bytes:
183        """Read this image bytes.
184
185        Returns
186        -------
187        `bytes`
188            The bytes of this image.
189        """
190        client_session = aiohttp.ClientSession()
191
192        try:
193            await client_session.__aenter__()
194            response = await client_session.get(self.create_url())
195
196            if 300 >= response.status >= 200:
197                reader = await response.read()
198
199        except Exception as exc:
200            raise RuntimeError(f"Failed to read image: {exc}") from None
201        finally:
202            await client_session.__aexit__(None, None, None)
203        return reader

Read this image bytes.

Returns
  • bytes: The bytes of this image.
async def iter(self) -> collections.abc.AsyncGenerator[bytes, None]:
205    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
206        """Iterates over the image bytes lazily.
207
208        Example
209        -------
210        import aiobungie
211
212        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
213        async for chunk in resource.iter():
214            print(chunk)
215
216        Returns
217        -------
218        `collections.AsyncGenerator[bytes, None]`
219            An async generator of the image bytes.
220        """
221
222        async for chunk in self:
223            yield chunk

Iterates over the image bytes lazily.

Example

import aiobungie

resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)

Returns
  • collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
@attrs.define(auto_exc=True)
class InternalServerError(aiobungie.HTTPException):
190@attrs.define(auto_exc=True)
191class InternalServerError(HTTPException):
192    """Raised for 5xx internal server errors."""

Raised for 5xx internal server errors.

InternalServerError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class InternalServerError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class ItemBindStatus(builtins.int, aiobungie.Enum):
722@typing.final
723class ItemBindStatus(int, Enum):
724    """An enum for Destiny 2 items bind status."""
725
726    NOT_BOUND = 0
727    BOUND_TO_CHARACTER = 1
728    BOUND_TO_ACCOUNT = 2
729    BOUNT_TO_GUILD = 3

An enum for Destiny 2 items bind status.

NOT_BOUND = <ItemBindStatus.NOT_BOUND: 0>
BOUND_TO_CHARACTER = <ItemBindStatus.BOUND_TO_CHARACTER: 1>
BOUND_TO_ACCOUNT = <ItemBindStatus.BOUND_TO_ACCOUNT: 2>
BOUNT_TO_GUILD = <ItemBindStatus.BOUNT_TO_GUILD: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemLocation(builtins.int, aiobungie.Enum):
732@typing.final
733class ItemLocation(int, Enum):
734    """An enum for Destiny 2 items location."""
735
736    UNKNOWN = 0
737    INVENTORY = 1
738    VAULT = 2
739    VENDOR = 3
740    POSTMASTER = 4

An enum for Destiny 2 items location.

UNKNOWN = <ItemLocation.UNKNOWN: 0>
INVENTORY = <ItemLocation.INVENTORY: 1>
VAULT = <ItemLocation.VAULT: 2>
VENDOR = <ItemLocation.VENDOR: 3>
POSTMASTER = <ItemLocation.POSTMASTER: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemState(aiobungie.Flag):
757@typing.final
758class ItemState(Flag):
759    """An enum for Destiny 2 item states."""
760
761    NONE = 0
762    LOCKED = 1
763    TRACKED = 2
764    MASTERWORKED = 4
765    CRAFTED = 8
766    """If this bit is set, the item has been 'crafted' by the player."""
767    HIGHLITED_OBJECTIVE = 16
768    """If this bit is set, the item is a 'highlighted' objective."""

An enum for Destiny 2 item states.

NONE = <ItemState.NONE: 0>
LOCKED = <ItemState.LOCKED: 1>
TRACKED = <ItemState.TRACKED: 2>
MASTERWORKED = <ItemState.MASTERWORKED: 4>
CRAFTED = <ItemState.CRAFTED: 8>

If this bit is set, the item has been 'crafted' by the player.

HIGHLITED_OBJECTIVE = <ItemState.HIGHLITED_OBJECTIVE: 16>

If this bit is set, the item is a 'highlighted' objective.

Inherited Members
Flag
name
value
@typing.final
class ItemSubType(builtins.int, aiobungie.Enum):
589@typing.final
590class ItemSubType(int, Enum):
591    """An enum for Destiny 2 inventory items subtype."""
592
593    NONE = 0
594    AUTORIFLE = 6
595    SHOTGUN = 7
596    MACHINEGUN = 8
597    HANDCANNON = 9
598    ROCKETLAUNCHER = 10
599    FUSIONRIFLE = 11
600    SNIPERRIFLE = 12
601    PULSERIFLE = 13
602    SCOUTRIFLE = 14
603    SIDEARM = 17
604    SWORD = 18
605    MASK = 19
606    SHADER = 20
607    ORNAMENT = 21
608    FUSIONRIFLELINE = 22
609    GRENADELAUNCHER = 23
610    SUBMACHINEGUN = 24
611    TRACERIFLE = 25
612    HELMETARMOR = 26
613    GAUNTLETSARMOR = 27
614    CHESTARMOR = 28
615    LEGARMOR = 29
616    CLASSARMOR = 30
617    BOW = 31
618    DUMMYREPEATABLEBOUNTY = 32

An enum for Destiny 2 inventory items subtype.

NONE = <ItemSubType.NONE: 0>
AUTORIFLE = <ItemSubType.AUTORIFLE: 6>
SHOTGUN = <ItemSubType.SHOTGUN: 7>
MACHINEGUN = <ItemSubType.MACHINEGUN: 8>
HANDCANNON = <ItemSubType.HANDCANNON: 9>
ROCKETLAUNCHER = <ItemSubType.ROCKETLAUNCHER: 10>
FUSIONRIFLE = <ItemSubType.FUSIONRIFLE: 11>
SNIPERRIFLE = <ItemSubType.SNIPERRIFLE: 12>
PULSERIFLE = <ItemSubType.PULSERIFLE: 13>
SCOUTRIFLE = <ItemSubType.SCOUTRIFLE: 14>
SIDEARM = <ItemSubType.SIDEARM: 17>
SWORD = <ItemSubType.SWORD: 18>
MASK = <ItemSubType.MASK: 19>
SHADER = <ItemSubType.SHADER: 20>
ORNAMENT = <ItemSubType.ORNAMENT: 21>
FUSIONRIFLELINE = <ItemSubType.FUSIONRIFLELINE: 22>
GRENADELAUNCHER = <ItemSubType.GRENADELAUNCHER: 23>
SUBMACHINEGUN = <ItemSubType.SUBMACHINEGUN: 24>
TRACERIFLE = <ItemSubType.TRACERIFLE: 25>
HELMETARMOR = <ItemSubType.HELMETARMOR: 26>
GAUNTLETSARMOR = <ItemSubType.GAUNTLETSARMOR: 27>
CHESTARMOR = <ItemSubType.CHESTARMOR: 28>
LEGARMOR = <ItemSubType.LEGARMOR: 29>
CLASSARMOR = <ItemSubType.CLASSARMOR: 30>
BOW = <ItemSubType.BOW: 31>
DUMMYREPEATABLEBOUNTY = <ItemSubType.DUMMYREPEATABLEBOUNTY: 32>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemTier(builtins.int, aiobungie.Enum):
621@typing.final
622class ItemTier(int, Enum):
623    """An enum for a Destiny 2 item tier."""
624
625    NONE = 0
626    BASIC = 3340296461
627    COMMON = 2395677314
628    RARE = 2127292149
629    LEGENDERY = 4008398120
630    EXOTIC = 2759499571

An enum for a Destiny 2 item tier.

NONE = <ItemTier.NONE: 0>
BASIC = <ItemTier.BASIC: 3340296461>
COMMON = <ItemTier.COMMON: 2395677314>
RARE = <ItemTier.RARE: 2127292149>
LEGENDERY = <ItemTier.LEGENDERY: 4008398120>
EXOTIC = <ItemTier.EXOTIC: 2759499571>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemType(builtins.int, aiobungie.Enum):
556@typing.final
557class ItemType(int, Enum):
558    """Enums for Destiny2's item types."""
559
560    NONE = 0
561    CURRENCY = 1
562    ARMOR = 2
563    WEAPON = 3
564    MESSAGE = 7
565    ENGRAM = 8
566    CONSUMABLE = 9
567    EXCHANGEMATERIAL = 10
568    MISSIONREWARD = 11
569    QUESTSTEP = 12
570    QUESTSTEPCOMPLETE = 13
571    EMBLEM = 14
572    QUEST = 15
573    SUBCLASS = 16
574    CLANBANNER = 17
575    AURA = 18
576    MOD = 19
577    DUMMY = 20
578    SHIP = 21
579    VEHICLE = 22
580    EMOTE = 23
581    GHOST = 24
582    PACKAGE = 25
583    BOUNTY = 26
584    WRAPPER = 27
585    SEASONALARTIFACT = 28
586    FINISHER = 29

Enums for Destiny2's item types.

NONE = <ItemType.NONE: 0>
CURRENCY = <ItemType.CURRENCY: 1>
ARMOR = <ItemType.ARMOR: 2>
WEAPON = <ItemType.WEAPON: 3>
MESSAGE = <ItemType.MESSAGE: 7>
ENGRAM = <ItemType.ENGRAM: 8>
CONSUMABLE = <ItemType.CONSUMABLE: 9>
EXCHANGEMATERIAL = <ItemType.EXCHANGEMATERIAL: 10>
MISSIONREWARD = <ItemType.MISSIONREWARD: 11>
QUESTSTEP = <ItemType.QUESTSTEP: 12>
QUESTSTEPCOMPLETE = <ItemType.QUESTSTEPCOMPLETE: 13>
EMBLEM = <ItemType.EMBLEM: 14>
QUEST = <ItemType.QUEST: 15>
SUBCLASS = <ItemType.SUBCLASS: 16>
CLANBANNER = <ItemType.CLANBANNER: 17>
AURA = <ItemType.AURA: 18>
MOD = <ItemType.MOD: 19>
DUMMY = <ItemType.DUMMY: 20>
SHIP = <ItemType.SHIP: 21>
VEHICLE = <ItemType.VEHICLE: 22>
EMOTE = <ItemType.EMOTE: 23>
GHOST = <ItemType.GHOST: 24>
PACKAGE = <ItemType.PACKAGE: 25>
BOUNTY = <ItemType.BOUNTY: 26>
WRAPPER = <ItemType.WRAPPER: 27>
SEASONALARTIFACT = <ItemType.SEASONALARTIFACT: 28>
FINISHER = <ItemType.FINISHER: 29>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class MembershipOption(builtins.int, aiobungie.Enum):
713@typing.final
714class MembershipOption(int, Enum):
715    """A enum for GroupV2 membership options."""
716
717    REVIEWD = 0
718    OPEN = 1
719    CLOSED = 2

A enum for GroupV2 membership options.

REVIEWD = <MembershipOption.REVIEWD: 0>
OPEN = <MembershipOption.OPEN: 1>
CLOSED = <MembershipOption.CLOSED: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class MembershipType(builtins.int, aiobungie.Enum):
463@typing.final
464class MembershipType(int, Enum):
465    """An Enum for Bungie membership types."""
466
467    NONE = 0
468    XBOX = 1
469    PSN = 2
470    STEAM = 3
471    BLIZZARD = 4
472    STADIA = 5
473    BUNGIE = 254
474    ALL = -1

An Enum for Bungie membership types.

NONE = <MembershipType.NONE: 0>
XBOX = <MembershipType.XBOX: 1>
PSN = <MembershipType.PSN: 2>
STEAM = <MembershipType.STEAM: 3>
BLIZZARD = <MembershipType.BLIZZARD: 4>
STADIA = <MembershipType.STADIA: 5>
BUNGIE = <MembershipType.BUNGIE: 254>
ALL = <MembershipType.ALL: -1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class MembershipTypeError(aiobungie.BadRequest):
163@attrs.define(auto_exc=True)
164class MembershipTypeError(BadRequest):
165    """A bad request error raised when passing wrong membership to the request.
166
167    Those fields are useful since it returns the correct membership and id which can be used
168    to make the request again with those fields.
169    """
170
171    membership_type: str = attrs.field(default="")
172    """The errored membership type passed to the request."""
173
174    membership_id: int = attrs.field(default=0)
175    """The errored user's membership id."""
176
177    required_membership: str = attrs.field(default="")
178    """The required correct membership for errored user."""
179
180    def __str__(self) -> str:
181        return (
182            f"Expected membership: {self.required_membership}, "
183            f"But got {self.membership_type} for id {self.membership_id}"
184        )
185
186    def __int__(self) -> int:
187        return int(self.membership_id)

A bad request error raised when passing wrong membership to the request.

Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.

MembershipTypeError( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], http_status: http.HTTPStatus = <HTTPStatus.BAD_REQUEST: 400>, membership_type: str = '', membership_id: int = 0, required_membership: str = '')
 2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default, membership_type=attr_dict['membership_type'].default, membership_id=attr_dict['membership_id'].default, required_membership=attr_dict['required_membership'].default):
 3    self.message = message
 4    self.url = url
 5    self.body = body
 6    self.headers = headers
 7    self.http_status = http_status
 8    self.membership_type = membership_type
 9    self.membership_id = membership_id
10    self.required_membership = required_membership
11    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status,self.membership_type,self.membership_id,self.required_membership)

Method generated by attrs for class MembershipTypeError.

membership_type: str

The errored membership type passed to the request.

membership_id: int

The errored user's membership id.

required_membership: str

The required correct membership for errored user.

Inherited Members
BadRequest
url
body
headers
http_status
HTTPError
message
builtins.BaseException
with_traceback
args
@typing.final
class MilestoneType(builtins.int, aiobungie.Enum):
506@typing.final
507class MilestoneType(int, Enum):
508    """An Enum for Destiny 2 milestone types."""
509
510    UNKNOWN = 0
511    TUTORIAL = 1
512    ONETIME = 2
513    WEEKLY = 3
514    DAILY = 4
515    SPECIAL = 5

An Enum for Destiny 2 milestone types.

UNKNOWN = <MilestoneType.UNKNOWN: 0>
TUTORIAL = <MilestoneType.TUTORIAL: 1>
ONETIME = <MilestoneType.ONETIME: 2>
WEEKLY = <MilestoneType.WEEKLY: 3>
DAILY = <MilestoneType.DAILY: 4>
SPECIAL = <MilestoneType.SPECIAL: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class NotFound(aiobungie.HTTPException):
129@attrs.define(auto_exc=True)
130class NotFound(HTTPException):
131    """Raised when an unknown request was not found."""
132
133    http_status: http.HTTPStatus = attrs.field(
134        default=http.HTTPStatus.NOT_FOUND, init=False
135    )

Raised when an unknown request was not found.

NotFound( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class NotFound.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class ObjectiveUIStyle(builtins.int, aiobungie.Enum):
 94@typing.final
 95class ObjectiveUIStyle(int, enums.Enum):
 96    NONE = 0
 97    HIGHLIGHTED = 1
 98    CRAFTING_WEAPON_LEVEL = 2
 99    CRAFTING_WEAPON_LEVEL_PROGRESS = 3
100    CRAFTING_WEAPON_TIMESTAMP = 4
101    CRAFTING_MEMENTOS = 5
102    CRAFTING_MEMENTO_TITLE = 6

An enumeration.

NONE = <ObjectiveUIStyle.NONE: 0>
HIGHLIGHTED = <ObjectiveUIStyle.HIGHLIGHTED: 1>
CRAFTING_WEAPON_LEVEL = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL: 2>
CRAFTING_WEAPON_LEVEL_PROGRESS = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL_PROGRESS: 3>
CRAFTING_WEAPON_TIMESTAMP = <ObjectiveUIStyle.CRAFTING_WEAPON_TIMESTAMP: 4>
CRAFTING_MEMENTOS = <ObjectiveUIStyle.CRAFTING_MEMENTOS: 5>
CRAFTING_MEMENTO_TITLE = <ObjectiveUIStyle.CRAFTING_MEMENTO_TITLE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Place(builtins.int, aiobungie.Enum):
235@typing.final
236class Place(int, Enum):
237    """An Enum for Destiny 2 Places and NOT Planets"""
238
239    ORBIT = 2961497387
240    SOCIAL = 4151112093
241    LIGHT_HOUSE = 4276116472
242    EXPLORE = 3497767639

An Enum for Destiny 2 Places and NOT Planets

ORBIT = <Place.ORBIT: 2961497387>
SOCIAL = <Place.SOCIAL: 4151112093>
LIGHT_HOUSE = <Place.LIGHT_HOUSE: 4276116472>
EXPLORE = <Place.EXPLORE: 3497767639>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Planet(builtins.int, aiobungie.Enum):
200@typing.final
201class Planet(int, Enum):
202    """An Enum for all available planets in Destiny 2."""
203
204    UNKNOWN = 0
205    """Unknown space"""
206
207    EARTH = 3747705955
208    """Earth"""
209
210    DREAMING_CITY = 2877881518
211    """The Dreaming city."""
212
213    NESSUS = 3526908984
214    """Nessus"""
215
216    MOON = 3325508439
217    """The Moon"""
218
219    COSMODROME = 3990611421
220    """The Cosmodrome"""
221
222    TANGLED_SHORE = 3821439926
223    """The Tangled Shore"""
224
225    VENUS = 3871070152
226    """Venus"""
227
228    EAZ = 541863059  # Exclusive event.
229    """European Aerial Zone"""
230
231    EUROPA = 1729879943
232    """Europa"""

An Enum for all available planets in Destiny 2.

UNKNOWN = <Planet.UNKNOWN: 0>

Unknown space

EARTH = <Planet.EARTH: 3747705955>

Earth

DREAMING_CITY = <Planet.DREAMING_CITY: 2877881518>

The Dreaming city.

NESSUS = <Planet.NESSUS: 3526908984>

Nessus

MOON = <Planet.MOON: 3325508439>

The Moon

COSMODROME = <Planet.COSMODROME: 3990611421>

The Cosmodrome

TANGLED_SHORE = <Planet.TANGLED_SHORE: 3821439926>

The Tangled Shore

VENUS = <Planet.VENUS: 3871070152>

Venus

EAZ = <Planet.EAZ: 541863059>

European Aerial Zone

EUROPA = <Planet.EUROPA: 1729879943>

Europa

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Presence(builtins.int, aiobungie.Enum):
683@typing.final
684class Presence(int, Enum):
685    """An enum for a bungie friend status."""
686
687    OFFLINE_OR_UNKNOWN = 0
688    ONLINE = 1

An enum for a bungie friend status.

OFFLINE_OR_UNKNOWN = <Presence.OFFLINE_OR_UNKNOWN: 0>
ONLINE = <Presence.ONLINE: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class PrivacySetting(builtins.int, aiobungie.Enum):
771@typing.final
772class PrivacySetting(int, Enum):
773    """An enum for players's privacy settings."""
774
775    OPEN = 0
776    CLAN_AND_FRIENDS = 1
777    FRIENDS_ONLY = 2
778    INVITE_ONLY = 3
779    CLOSED = 4

An enum for players's privacy settings.

OPEN = <PrivacySetting.OPEN: 0>
CLAN_AND_FRIENDS = <PrivacySetting.CLAN_AND_FRIENDS: 1>
FRIENDS_ONLY = <PrivacySetting.FRIENDS_ONLY: 2>
INVITE_ONLY = <PrivacySetting.INVITE_ONLY: 3>
CLOSED = <PrivacySetting.CLOSED: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RESTClient(aiobungie.interfaces.rest.RESTInterface):
 364class RESTClient(interfaces.RESTInterface):
 365    """A RESTful client implementation for Bungie's API.
 366
 367    This client is designed to only make HTTP requests and return JSON objects
 368    to provide RESTful functionality.
 369
 370    This client is also used within `aiobungie.Client` which deserialize those returned JSON objects
 371    using the factory into Pythonic data classes objects which provide Python functionality.
 372
 373    Example
 374    -------
 375    ```py
 376    import aiobungie
 377
 378    async def main():
 379        async with aiobungie.RESTClient("TOKEN") as rest_client:
 380            req = await rest_client.fetch_clan_members(4389205)
 381            clan_members = req['results']
 382            for member in clan_members:
 383                for k, v in member['destinyUserInfo'].items():
 384                    print(k, v)
 385    ```
 386
 387    Parameters
 388    ----------
 389    token : `str`
 390        A valid application token from Bungie's developer portal.
 391
 392    Other Parameters
 393    ----------------
 394    max_retries : `int`
 395        The max retries number to retry if the request hit a `5xx` status code.
 396    max_ratelimit_retries : `int`
 397        The max retries number to retry if the request hit a `429` status code. Defaults to `3`.
 398    client_secret : `typing.Optional[str]`
 399        An optional application client secret,
 400        This is only needed if you're fetching OAuth2 tokens with this client.
 401    client_id : `typing.Optional[int]`
 402        An optional application client id,
 403        This is only needed if you're fetching OAuth2 tokens with this client.
 404    enable_debugging : `bool | str`
 405        Whether to enable logging responses or not.
 406
 407    Logging Levels
 408    --------------
 409    * `False`: This will disable logging.
 410    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
 411    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
 412    """
 413
 414    __slots__ = (
 415        "_token",
 416        "_session",
 417        "_lock",
 418        "_max_retries",
 419        "_client_secret",
 420        "_client_id",
 421        "_metadata",
 422        "_max_rate_limit_retries",
 423    )
 424
 425    def __init__(
 426        self,
 427        token: str,
 428        /,
 429        client_secret: typing.Optional[str] = None,
 430        client_id: typing.Optional[int] = None,
 431        *,
 432        max_retries: int = 4,
 433        max_ratelimit_retries: int = 3,
 434        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 435    ) -> None:
 436        self._session: typing.Optional[_Session] = None
 437        self._lock: typing.Optional[asyncio.Lock] = None
 438        self._client_secret = client_secret
 439        self._client_id = client_id
 440        self._token: str = token
 441        self._max_retries = max_retries
 442        self._max_rate_limit_retries = max_ratelimit_retries
 443        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
 444
 445        self._set_debug_level(enable_debugging)
 446
 447    @property
 448    def client_id(self) -> typing.Optional[int]:
 449        return self._client_id
 450
 451    @property
 452    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 453        return self._metadata
 454
 455    @property
 456    def is_alive(self) -> bool:
 457        return self._session is not None
 458
 459    @typing.final
 460    async def close(self) -> None:
 461        session = self._get_session()
 462        await session.close()
 463        self._session = None
 464
 465    @typing.final
 466    def open(self) -> None:
 467        """Open a new client session. This is called internally with contextmanager usage."""
 468        if self.is_alive:
 469            raise RuntimeError("Cannot open a new session while it's already open.")
 470
 471        self._session = _Session.create(
 472            owner=False,
 473            raise_status=False,
 474            connect=None,
 475            socket_read=None,
 476            socket_connect=None,
 477        )
 478
 479    @typing.final
 480    def enable_debugging(
 481        self,
 482        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 483        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 484        /,
 485    ) -> None:
 486        self._set_debug_level(level, file)
 487
 488    @typing.final
 489    async def static_request(
 490        self,
 491        method: typing.Union[RequestMethod, str],
 492        path: str,
 493        *,
 494        auth: typing.Optional[str] = None,
 495        json: typing.Optional[dict[str, typing.Any]] = None,
 496    ) -> ResponseSig:
 497        return await self._request(method, path, auth=auth, json=json)
 498
 499    @typing.final
 500    def build_oauth2_url(
 501        self, client_id: typing.Optional[int] = None
 502    ) -> typing.Optional[str]:
 503        client_id = client_id or self._client_id
 504        if client_id is None:
 505            return None
 506
 507        return url.OAUTH2_EP_BUILDER.format(
 508            oauth_endpoint=url.OAUTH_EP,
 509            client_id=client_id,
 510            uuid=_uuid(),
 511        )
 512
 513    @staticmethod
 514    def _set_debug_level(
 515        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 516        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 517    ) -> None:
 518
 519        file_handler = logging.FileHandler(file, mode="w") if file else None
 520        if level == "TRACE" or level == TRACE:
 521            logging.basicConfig(
 522                level=TRACE, handlers=[file_handler] if file_handler else None
 523            )
 524
 525        elif level:
 526            logging.basicConfig(
 527                level=logging.DEBUG, handlers=[file_handler] if file_handler else None
 528            )
 529
 530    def _get_session(self) -> _Session:
 531        if self._session:
 532            return self._session
 533
 534        raise RuntimeError(
 535            "Cannot return a session while its close. Make sure you use `async with` before making requests."
 536        )
 537
 538    async def _request(
 539        self,
 540        method: typing.Union[RequestMethod, str],
 541        route: str,
 542        *,
 543        base: bool = False,
 544        oauth2: bool = False,
 545        auth: typing.Optional[str] = None,
 546        unwrapping: typing.Literal["json", "read"] = "json",
 547        json: typing.Optional[dict[str, typing.Any]] = None,
 548        headers: typing.Optional[dict[str, typing.Any]] = None,
 549        data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None,
 550    ) -> ResponseSig:
 551
 552        retries: int = 0
 553        session = self._get_session()
 554        headers = headers or {}
 555
 556        headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT)
 557        headers["X-API-KEY"] = self._token
 558
 559        if auth is not None:
 560            headers[_AUTH_HEADER] = f"Bearer {auth}"
 561
 562        # Handling endpoints
 563        endpoint = url.BASE
 564
 565        if not base:
 566            endpoint = endpoint + url.REST_EP
 567
 568        if oauth2:
 569            headers["Content-Type"] = "application/x-www-form-urlencoded"
 570            endpoint = endpoint + url.TOKEN_EP
 571
 572        if self._lock is None:
 573            self._lock = asyncio.Lock()
 574
 575        while True:
 576            try:
 577                async with (stack := contextlib.AsyncExitStack()):
 578                    await stack.enter_async_context(self._lock)
 579
 580                    # We make the request here.
 581                    taken_time = time.monotonic()
 582                    response = await stack.enter_async_context(
 583                        session.client_session.request(
 584                            method=method,
 585                            url=f"{endpoint}/{route}",
 586                            json=json,
 587                            headers=headers,
 588                            data=data,
 589                        )
 590                    )
 591                    response_time = (time.monotonic() - taken_time) * 1_000
 592
 593                    _LOG.debug(
 594                        "%s %s %s Time %.4fms",
 595                        method,
 596                        f"{endpoint}/{route}",
 597                        f"{response.status} {response.reason}",
 598                        response_time,
 599                    )
 600
 601                    await self._handle_ratelimit(
 602                        response, method, route, self._max_rate_limit_retries
 603                    )
 604
 605                    if response.status == http.HTTPStatus.NO_CONTENT:
 606                        return None
 607
 608                    if 300 > response.status >= 200:
 609                        if unwrapping == "read":
 610                            # We need to read the bytes for the manifest response.
 611                            return await response.read()
 612
 613                        if response.content_type == _APP_JSON:
 614                            json_data = await response.json()
 615
 616                            _LOG.debug(
 617                                "%s %s %s Time %.4fms",
 618                                method,
 619                                f"{endpoint}/{route}",
 620                                f"{response.status} {response.reason}",
 621                                response_time,
 622                            )
 623
 624                            if _LOG.isEnabledFor(TRACE):
 625                                headers.update(response.headers)  # type: ignore
 626
 627                                _LOG.log(
 628                                    TRACE,
 629                                    "%s",
 630                                    error.stringify_http_message(headers),
 631                                )
 632
 633                            # Return the response.
 634                            # oauth2 responses are not packed inside a Response object.
 635                            if oauth2:
 636                                return json_data  # type: ignore[no-any-return]
 637
 638                            return json_data["Response"]  # type: ignore[no-any-return]
 639
 640                    if (
 641                        response.status in _RETRY_5XX
 642                        and retries < self._max_retries  # noqa: W503
 643                    ):
 644                        backoff_ = backoff.ExponentialBackOff(maximum=6)
 645                        sleep_time = next(backoff_)
 646                        _LOG.warning(
 647                            "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i",
 648                            response.status,
 649                            response.reason,
 650                            sleep_time,
 651                            self._max_retries - retries,
 652                        )
 653
 654                        retries += 1
 655                        await asyncio.sleep(sleep_time)
 656                        continue
 657
 658                    raise await error.raise_error(response)
 659            # eol
 660            except _Dyn:
 661                continue
 662
 663    if not typing.TYPE_CHECKING:
 664
 665        def __enter__(self) -> typing.NoReturn:
 666            cls = type(self)
 667            raise TypeError(
 668                f"{cls.__qualname__} is async only, use 'async with' instead."
 669            )
 670
 671        def __exit__(
 672            self,
 673            exception_type: typing.Optional[type[BaseException]],
 674            exception: typing.Optional[BaseException],
 675            exception_traceback: typing.Optional[types.TracebackType],
 676        ) -> None:
 677            ...
 678
 679    async def __aenter__(self) -> RESTClient:
 680        self.open()
 681        return self
 682
 683    async def __aexit__(
 684        self,
 685        exception_type: typing.Optional[type[BaseException]],
 686        exception: typing.Optional[BaseException],
 687        exception_traceback: typing.Optional[types.TracebackType],
 688    ) -> None:
 689        await self.close()
 690
 691    # We don't want this to be super complicated.
 692    @staticmethod
 693    @typing.final
 694    async def _handle_ratelimit(
 695        response: aiohttp.ClientResponse,
 696        method: str,
 697        route: str,
 698        max_ratelimit_retries: int = 3,
 699    ) -> None:
 700
 701        if response.status != http.HTTPStatus.TOO_MANY_REQUESTS:
 702            return
 703
 704        if response.content_type != _APP_JSON:
 705            raise error.HTTPError(
 706                f"Being ratelimited on non JSON request, {response.content_type}.",
 707                http.HTTPStatus.TOO_MANY_REQUESTS,
 708            )
 709
 710        count: int = 0
 711        json: typedefs.JSONObject = await response.json()
 712        retry_after = float(json["ThrottleSeconds"])
 713
 714        while True:
 715            if count == max_ratelimit_retries:
 716                raise _Dyn
 717
 718            if retry_after <= 0:
 719                # We sleep for a little bit to avoid funky behavior.
 720                sleep_time = float(random.random() + 0.93) / 2
 721
 722                _LOG.warning(
 723                    "We're being ratelimited with method %s route %s. Sleeping for %.2fs.",
 724                    method,
 725                    route,
 726                    sleep_time,
 727                )
 728                count += 1
 729                await asyncio.sleep(sleep_time)
 730                continue
 731
 732            raise error.RateLimitedError(
 733                body=json,
 734                url=str(response.real_url),
 735                retry_after=retry_after,
 736            )
 737
 738    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
 739
 740        if not isinstance(self._client_id, int):
 741            raise TypeError(
 742                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
 743            )
 744
 745        if not isinstance(self._client_secret, str):
 746            raise TypeError(
 747                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
 748            )
 749
 750        headers = {
 751            "client_secret": self._client_secret,
 752        }
 753
 754        data = (
 755            f"grant_type=authorization_code&code={code}"
 756            f"&client_id={self._client_id}&client_secret={self._client_secret}"
 757        )
 758
 759        response = await self._request(
 760            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
 761        )
 762        assert isinstance(response, dict)
 763        return builders.OAuth2Response.build_response(response)
 764
 765    async def refresh_access_token(
 766        self, refresh_token: str, /
 767    ) -> builders.OAuth2Response:
 768        if not isinstance(self._client_id, int):
 769            raise TypeError(
 770                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
 771            )
 772
 773        if not isinstance(self._client_secret, str):
 774            raise TypeError(
 775                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
 776            )
 777
 778        data = {
 779            "grant_type": "refresh_token",
 780            "refresh_token": refresh_token,
 781            "client_id": self._client_id,
 782            "client_secret": self._client_secret,
 783            "Content-Type": "application/x-www-form-urlencoded",
 784        }
 785
 786        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
 787        assert isinstance(response, dict)
 788        return builders.OAuth2Response.build_response(response)
 789
 790    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
 791        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 792        resp = await self._request(
 793            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
 794        )
 795        assert isinstance(resp, dict)
 796        return resp
 797
 798    async def fetch_user_themes(self) -> typedefs.JSONArray:
 799        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 800        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
 801        assert isinstance(resp, list)
 802        return resp
 803
 804    async def fetch_membership_from_id(
 805        self,
 806        id: int,
 807        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 808        /,
 809    ) -> typedefs.JSONObject:
 810        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 811        resp = await self._request(
 812            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
 813        )
 814        assert isinstance(resp, dict)
 815        return resp
 816
 817    async def fetch_player(
 818        self,
 819        name: str,
 820        code: int,
 821        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 822        /,
 823    ) -> typedefs.JSONArray:
 824        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 825        resp = await self._request(
 826            RequestMethod.POST,
 827            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
 828            json={"displayName": name, "displayNameCode": code},
 829        )
 830        assert isinstance(resp, list)
 831        return resp
 832
 833    async def search_users(self, name: str, /) -> typedefs.JSONObject:
 834        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 835        resp = await self._request(
 836            RequestMethod.POST,
 837            "User/Search/GlobalName/0",
 838            json={"displayNamePrefix": name},
 839        )
 840        assert isinstance(resp, dict)
 841        return resp
 842
 843    async def fetch_clan_from_id(
 844        self, id: int, /, access_token: typing.Optional[str] = None
 845    ) -> typedefs.JSONObject:
 846        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 847        resp = await self._request(
 848            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
 849        )
 850        assert isinstance(resp, dict)
 851        return resp
 852
 853    async def fetch_clan(
 854        self,
 855        name: str,
 856        /,
 857        access_token: typing.Optional[str] = None,
 858        *,
 859        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 860    ) -> typedefs.JSONObject:
 861        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 862        resp = await self._request(
 863            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
 864        )
 865        assert isinstance(resp, dict)
 866        return resp
 867
 868    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
 869        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 870        resp = await self._request(
 871            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
 872        )
 873        assert isinstance(resp, dict)
 874        return resp
 875
 876    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
 877        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 878        resp = await self._request(
 879            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
 880        )
 881        assert isinstance(resp, list)
 882        return resp
 883
 884    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
 885        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 886        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
 887        assert isinstance(resp, dict)
 888        return resp
 889
 890    async def fetch_character(
 891        self,
 892        member_id: int,
 893        membership_type: typedefs.IntAnd[enums.MembershipType],
 894        character_id: int,
 895        components: list[enums.ComponentType],
 896        auth: typing.Optional[str] = None,
 897    ) -> typedefs.JSONObject:
 898        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 899        collector = _collect_components(components)
 900        response = await self._request(
 901            RequestMethod.GET,
 902            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
 903            f"Character/{character_id}/?components={collector}",
 904            auth=auth,
 905        )
 906        assert isinstance(response, dict)
 907        return response
 908
 909    async def fetch_activities(
 910        self,
 911        member_id: int,
 912        character_id: int,
 913        mode: typedefs.IntAnd[enums.GameMode],
 914        membership_type: typedefs.IntAnd[
 915            enums.MembershipType
 916        ] = enums.MembershipType.ALL,
 917        *,
 918        page: int = 0,
 919        limit: int = 1,
 920    ) -> typedefs.JSONObject:
 921        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 922        resp = await self._request(
 923            RequestMethod.GET,
 924            f"Destiny2/{int(membership_type)}/Account/"
 925            f"{member_id}/Character/{character_id}/Stats/Activities"
 926            f"/?mode={int(mode)}&count={limit}&page={page}",
 927        )
 928        assert isinstance(resp, dict)
 929        return resp
 930
 931    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
 932        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 933        resp = await self._request(
 934            RequestMethod.GET,
 935            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
 936        )
 937        assert isinstance(resp, dict)
 938        return resp
 939
 940    async def fetch_profile(
 941        self,
 942        membership_id: int,
 943        type: typedefs.IntAnd[enums.MembershipType],
 944        components: list[enums.ComponentType],
 945        auth: typing.Optional[str] = None,
 946    ) -> typedefs.JSONObject:
 947        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 948        collector = _collect_components(components)
 949        response = await self._request(
 950            RequestMethod.GET,
 951            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
 952            auth=auth,
 953        )
 954        assert isinstance(response, dict)
 955        return response
 956
 957    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
 958        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 959        response = await self._request(
 960            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
 961        )
 962        assert isinstance(response, dict)
 963        return response
 964
 965    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
 966        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 967        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
 968        assert isinstance(resp, dict)
 969        return resp
 970
 971    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
 972        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 973        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
 974        assert isinstance(resp, dict)
 975        return resp
 976
 977    async def fetch_groups_for_member(
 978        self,
 979        member_id: int,
 980        member_type: typedefs.IntAnd[enums.MembershipType],
 981        /,
 982        *,
 983        filter: int = 0,
 984        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 985    ) -> typedefs.JSONObject:
 986        resp = await self._request(
 987            RequestMethod.GET,
 988            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 989        )
 990        assert isinstance(resp, dict)
 991        return resp
 992
 993    async def fetch_potential_groups_for_member(
 994        self,
 995        member_id: int,
 996        member_type: typedefs.IntAnd[enums.MembershipType],
 997        /,
 998        *,
 999        filter: int = 0,
1000        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
1001    ) -> typedefs.JSONObject:
1002        resp = await self._request(
1003            RequestMethod.GET,
1004            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
1005        )
1006        assert isinstance(resp, dict)
1007        return resp
1008
1009    async def fetch_clan_members(
1010        self,
1011        clan_id: int,
1012        /,
1013        *,
1014        name: typing.Optional[str] = None,
1015        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
1016    ) -> typedefs.JSONObject:
1017        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1018        resp = await self._request(
1019            RequestMethod.GET,
1020            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
1021        )
1022        assert isinstance(resp, dict)
1023        return resp
1024
1025    async def fetch_hardlinked_credentials(
1026        self,
1027        credential: int,
1028        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
1029        /,
1030    ) -> typedefs.JSONObject:
1031        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1032        resp = await self._request(
1033            RequestMethod.GET,
1034            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
1035        )
1036        assert isinstance(resp, dict)
1037        return resp
1038
1039    async def fetch_user_credentials(
1040        self, access_token: str, membership_id: int, /
1041    ) -> typedefs.JSONArray:
1042        resp = await self._request(
1043            RequestMethod.GET,
1044            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
1045            auth=access_token,
1046        )
1047        assert isinstance(resp, list)
1048        return resp
1049
1050    async def insert_socket_plug(
1051        self,
1052        action_token: str,
1053        /,
1054        instance_id: int,
1055        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1056        character_id: int,
1057        membership_type: typedefs.IntAnd[enums.MembershipType],
1058    ) -> typedefs.JSONObject:
1059
1060        if isinstance(plug, builders.PlugSocketBuilder):
1061            plug = plug.collect()
1062
1063        body = {
1064            "actionToken": action_token,
1065            "itemInstanceId": instance_id,
1066            "plug": plug,
1067            "characterId": character_id,
1068            "membershipType": int(membership_type),
1069        }
1070        resp = await self._request(
1071            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
1072        )
1073        assert isinstance(resp, dict)
1074        return resp
1075
1076    async def insert_socket_plug_free(
1077        self,
1078        access_token: str,
1079        /,
1080        instance_id: int,
1081        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1082        character_id: int,
1083        membership_type: typedefs.IntAnd[enums.MembershipType],
1084    ) -> typedefs.JSONObject:
1085
1086        if isinstance(plug, builders.PlugSocketBuilder):
1087            plug = plug.collect()
1088
1089        body = {
1090            "itemInstanceId": instance_id,
1091            "plug": plug,
1092            "characterId": character_id,
1093            "membershipType": int(membership_type),
1094        }
1095        resp = await self._request(
1096            RequestMethod.POST,
1097            "Destiny2/Actions/Items/InsertSocketPlugFree",
1098            json=body,
1099            auth=access_token,
1100        )
1101        assert isinstance(resp, dict)
1102        return resp
1103
1104    async def set_item_lock_state(
1105        self,
1106        access_token: str,
1107        state: bool,
1108        /,
1109        item_id: int,
1110        character_id: int,
1111        membership_type: typedefs.IntAnd[enums.MembershipType],
1112    ) -> int:
1113        body = {
1114            "state": state,
1115            "itemId": item_id,
1116            "characterId": character_id,
1117            "membership_type": int(membership_type),
1118        }
1119        response = await self._request(
1120            RequestMethod.POST,
1121            "Destiny2/Actions/Items/SetLockState",
1122            json=body,
1123            auth=access_token,
1124        )
1125        assert isinstance(response, int)
1126        return response
1127
1128    async def set_quest_track_state(
1129        self,
1130        access_token: str,
1131        state: bool,
1132        /,
1133        item_id: int,
1134        character_id: int,
1135        membership_type: typedefs.IntAnd[enums.MembershipType],
1136    ) -> int:
1137        body = {
1138            "state": state,
1139            "itemId": item_id,
1140            "characterId": character_id,
1141            "membership_type": int(membership_type),
1142        }
1143        response = await self._request(
1144            RequestMethod.POST,
1145            "Destiny2/Actions/Items/SetTrackedState",
1146            json=body,
1147            auth=access_token,
1148        )
1149        assert isinstance(response, int)
1150        return response
1151
1152    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1153        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1154        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1155        assert isinstance(path, dict)
1156        return path
1157
1158    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1159        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1160        _ensure_manifest_language(language)
1161
1162        content = await self.fetch_manifest_path()
1163        resp = await self._request(
1164            RequestMethod.GET,
1165            content["mobileWorldContentPaths"][language],
1166            unwrapping="read",
1167            base=True,
1168        )
1169        assert isinstance(resp, bytes)
1170        return resp
1171
1172    async def download_manifest(
1173        self,
1174        language: str = "en",
1175        name: str = "manifest",
1176        path: typing.Union[pathlib.Path, str] = ".",
1177        *,
1178        force: bool = False,
1179    ) -> None:
1180        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1181        complete_path = _get_path(name, path, sql=True)
1182
1183        if complete_path.exists() and force:
1184            if force:
1185                _LOG.info(
1186                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1187                )
1188                complete_path.unlink(missing_ok=True)
1189
1190                return await self.download_manifest(language, name, path, force=force)
1191
1192            else:
1193                raise FileExistsError(
1194                    "Manifest file already exists, "
1195                    "To force download, set the `force` parameter to `True`."
1196                )
1197
1198        _LOG.info(f"Downloading manifest. Location: {complete_path!s}")
1199        data_bytes = await self.read_manifest_bytes(language)
1200        await asyncio.get_running_loop().run_in_executor(
1201            None, _write_sqlite_bytes, data_bytes, path, name
1202        )
1203
1204    async def download_json_manifest(
1205        self,
1206        file_name: str = "manifest",
1207        path: typing.Union[str, pathlib.Path] = ".",
1208        language: str = "en",
1209    ) -> None:
1210        _ensure_manifest_language(language)
1211
1212        _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...")
1213
1214        content = await self.fetch_manifest_path()
1215        json_bytes = await self._request(
1216            RequestMethod.GET,
1217            content["jsonWorldContentPaths"][language],
1218            unwrapping="read",
1219            base=True,
1220        )
1221
1222        await asyncio.get_running_loop().run_in_executor(
1223            None, _write_json_bytes, json_bytes, file_name, path
1224        )
1225        _LOG.info("Finished downloading manifest JSON.")
1226
1227    async def fetch_manifest_version(self) -> str:
1228        return typing.cast(str, (await self.fetch_manifest_path())["version"])
1229
1230    async def fetch_linked_profiles(
1231        self,
1232        member_id: int,
1233        member_type: typedefs.IntAnd[enums.MembershipType],
1234        /,
1235        *,
1236        all: bool = False,
1237    ) -> typedefs.JSONObject:
1238        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1239        resp = await self._request(
1240            RequestMethod.GET,
1241            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1242        )
1243        assert isinstance(resp, dict)
1244        return resp
1245
1246    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1247        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1248        resp = await self._request(
1249            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1250        )
1251        assert isinstance(resp, dict)
1252        return resp
1253
1254    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1255        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1256        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1257        assert isinstance(resp, dict)
1258        return resp
1259
1260    async def fetch_public_milestone_content(
1261        self, milestone_hash: int, /
1262    ) -> typedefs.JSONObject:
1263        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1264        resp = await self._request(
1265            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1266        )
1267        assert isinstance(resp, dict)
1268        return resp
1269
1270    async def fetch_current_user_memberships(
1271        self, access_token: str, /
1272    ) -> typedefs.JSONObject:
1273        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1274        resp = await self._request(
1275            RequestMethod.GET,
1276            "User/GetMembershipsForCurrentUser/",
1277            auth=access_token,
1278        )
1279        assert isinstance(resp, dict)
1280        return resp
1281
1282    async def equip_item(
1283        self,
1284        access_token: str,
1285        /,
1286        item_id: int,
1287        character_id: int,
1288        membership_type: typedefs.IntAnd[enums.MembershipType],
1289    ) -> None:
1290        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1291        payload = {
1292            "itemId": item_id,
1293            "characterId": character_id,
1294            "membershipType": int(membership_type),
1295        }
1296
1297        await self._request(
1298            RequestMethod.POST,
1299            "Destiny2/Actions/Items/EquipItem/",
1300            json=payload,
1301            auth=access_token,
1302        )
1303
1304    async def equip_items(
1305        self,
1306        access_token: str,
1307        /,
1308        item_ids: list[int],
1309        character_id: int,
1310        membership_type: typedefs.IntAnd[enums.MembershipType],
1311    ) -> None:
1312        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1313        payload = {
1314            "itemIds": item_ids,
1315            "characterId": character_id,
1316            "membershipType": int(membership_type),
1317        }
1318        await self._request(
1319            RequestMethod.POST,
1320            "Destiny2/Actions/Items/EquipItems/",
1321            json=payload,
1322            auth=access_token,
1323        )
1324
1325    async def ban_clan_member(
1326        self,
1327        access_token: str,
1328        /,
1329        group_id: int,
1330        membership_id: int,
1331        membership_type: typedefs.IntAnd[enums.MembershipType],
1332        *,
1333        length: int = 0,
1334        comment: undefined.UndefinedOr[str] = undefined.Undefined,
1335    ) -> None:
1336        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1337        payload = {"comment": str(comment), "length": length}
1338        await self._request(
1339            RequestMethod.POST,
1340            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1341            json=payload,
1342            auth=access_token,
1343        )
1344
1345    async def unban_clan_member(
1346        self,
1347        access_token: str,
1348        /,
1349        group_id: int,
1350        membership_id: int,
1351        membership_type: typedefs.IntAnd[enums.MembershipType],
1352    ) -> None:
1353        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1354        await self._request(
1355            RequestMethod.POST,
1356            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1357            auth=access_token,
1358        )
1359
1360    async def kick_clan_member(
1361        self,
1362        access_token: str,
1363        /,
1364        group_id: int,
1365        membership_id: int,
1366        membership_type: typedefs.IntAnd[enums.MembershipType],
1367    ) -> typedefs.JSONObject:
1368        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1369        resp = await self._request(
1370            RequestMethod.POST,
1371            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1372            auth=access_token,
1373        )
1374        assert isinstance(resp, dict)
1375        return resp
1376
1377    async def edit_clan(
1378        self,
1379        access_token: str,
1380        /,
1381        group_id: int,
1382        *,
1383        name: typedefs.NoneOr[str] = None,
1384        about: typedefs.NoneOr[str] = None,
1385        motto: typedefs.NoneOr[str] = None,
1386        theme: typedefs.NoneOr[str] = None,
1387        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1388        is_public: typedefs.NoneOr[bool] = None,
1389        locale: typedefs.NoneOr[str] = None,
1390        avatar_image_index: typedefs.NoneOr[int] = None,
1391        membership_option: typedefs.NoneOr[
1392            typedefs.IntAnd[enums.MembershipOption]
1393        ] = None,
1394        allow_chat: typedefs.NoneOr[bool] = None,
1395        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1396        call_sign: typedefs.NoneOr[str] = None,
1397        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1398        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1399        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1400        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1401    ) -> None:
1402        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1403        payload = {
1404            "name": name,
1405            "about": about,
1406            "motto": motto,
1407            "theme": theme,
1408            "tags": tags,
1409            "isPublic": is_public,
1410            "avatarImageIndex": avatar_image_index,
1411            "isPublicTopicAdminOnly": is_public_topic_admin,
1412            "allowChat": allow_chat,
1413            "chatSecurity": chat_security,
1414            "callsign": call_sign,
1415            "homepage": homepage,
1416            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1417            "defaultPublicity": default_publicity,
1418            "locale": locale,
1419        }
1420        if membership_option is not None:
1421            payload["membershipOption"] = int(membership_option)
1422
1423        await self._request(
1424            RequestMethod.POST,
1425            f"GroupV2/{group_id}/Edit",
1426            json=payload,
1427            auth=access_token,
1428        )
1429
1430    async def edit_clan_options(
1431        self,
1432        access_token: str,
1433        /,
1434        group_id: int,
1435        *,
1436        invite_permissions_override: typedefs.NoneOr[bool] = None,
1437        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1438        host_guided_game_permission_override: typedefs.NoneOr[
1439            typing.Literal[0, 1, 2]
1440        ] = None,
1441        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1442        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1443    ) -> None:
1444
1445        payload = {
1446            "InvitePermissionOverride": invite_permissions_override,
1447            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1448            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1449            "UpdateBannerPermissionOverride": update_banner_permission_override,
1450            "JoinLevel": int(join_level) if join_level else None,
1451        }
1452
1453        await self._request(
1454            RequestMethod.POST,
1455            f"GroupV2/{group_id}/EditFounderOptions",
1456            json=payload,
1457            auth=access_token,
1458        )
1459
1460    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1461        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1462        resp = await self._request(
1463            RequestMethod.GET,
1464            "Social/Friends/",
1465            auth=access_token,
1466        )
1467        assert isinstance(resp, dict)
1468        return resp
1469
1470    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1471        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1472        resp = await self._request(
1473            RequestMethod.GET,
1474            "Social/Friends/Requests",
1475            auth=access_token,
1476        )
1477        assert isinstance(resp, dict)
1478        return resp
1479
1480    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1481        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1482        await self._request(
1483            RequestMethod.POST,
1484            f"Social/Friends/Requests/Accept/{member_id}",
1485            auth=access_token,
1486        )
1487
1488    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1489        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1490        await self._request(
1491            RequestMethod.POST,
1492            f"Social/Friends/Add/{member_id}",
1493            auth=access_token,
1494        )
1495
1496    async def decline_friend_request(
1497        self, access_token: str, /, member_id: int
1498    ) -> None:
1499        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1500        await self._request(
1501            RequestMethod.POST,
1502            f"Social/Friends/Requests/Decline/{member_id}",
1503            auth=access_token,
1504        )
1505
1506    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1507        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1508        await self._request(
1509            RequestMethod.POST,
1510            f"Social/Friends/Remove/{member_id}",
1511            auth=access_token,
1512        )
1513
1514    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1515        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1516        await self._request(
1517            RequestMethod.POST,
1518            f"Social/Friends/Requests/Remove/{member_id}",
1519            auth=access_token,
1520        )
1521
1522    async def approve_all_pending_group_users(
1523        self,
1524        access_token: str,
1525        /,
1526        group_id: int,
1527        message: undefined.UndefinedOr[str] = undefined.Undefined,
1528    ) -> None:
1529        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1530        await self._request(
1531            RequestMethod.POST,
1532            f"GroupV2/{group_id}/Members/ApproveAll",
1533            auth=access_token,
1534            json={"message": str(message)},
1535        )
1536
1537    async def deny_all_pending_group_users(
1538        self,
1539        access_token: str,
1540        /,
1541        group_id: int,
1542        *,
1543        message: undefined.UndefinedOr[str] = undefined.Undefined,
1544    ) -> None:
1545        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1546        await self._request(
1547            RequestMethod.POST,
1548            f"GroupV2/{group_id}/Members/DenyAll",
1549            auth=access_token,
1550            json={"message": str(message)},
1551        )
1552
1553    async def add_optional_conversation(
1554        self,
1555        access_token: str,
1556        /,
1557        group_id: int,
1558        *,
1559        name: undefined.UndefinedOr[str] = undefined.Undefined,
1560        security: typing.Literal[0, 1] = 0,
1561    ) -> None:
1562        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1563        payload = {"chatName": str(name), "chatSecurity": security}
1564        await self._request(
1565            RequestMethod.POST,
1566            f"GroupV2/{group_id}/OptionalConversations/Add",
1567            json=payload,
1568            auth=access_token,
1569        )
1570
1571    async def edit_optional_conversation(
1572        self,
1573        access_token: str,
1574        /,
1575        group_id: int,
1576        conversation_id: int,
1577        *,
1578        name: undefined.UndefinedOr[str] = undefined.Undefined,
1579        security: typing.Literal[0, 1] = 0,
1580        enable_chat: bool = False,
1581    ) -> None:
1582        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1583        payload = {
1584            "chatEnabled": enable_chat,
1585            "chatName": str(name),
1586            "chatSecurity": security,
1587        }
1588        await self._request(
1589            RequestMethod.POST,
1590            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1591            json=payload,
1592            auth=access_token,
1593        )
1594
1595    async def transfer_item(
1596        self,
1597        access_token: str,
1598        /,
1599        item_id: int,
1600        item_hash: int,
1601        character_id: int,
1602        member_type: typedefs.IntAnd[enums.MembershipType],
1603        *,
1604        stack_size: int = 1,
1605        vault: bool = False,
1606    ) -> None:
1607        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1608        payload = {
1609            "characterId": character_id,
1610            "membershipType": int(member_type),
1611            "itemId": item_id,
1612            "itemReferenceHash": item_hash,
1613            "stackSize": stack_size,
1614            "transferToVault": vault,
1615        }
1616        await self._request(
1617            RequestMethod.POST,
1618            "Destiny2/Actions/Items/TransferItem",
1619            json=payload,
1620            auth=access_token,
1621        )
1622
1623    async def pull_item(
1624        self,
1625        access_token: str,
1626        /,
1627        item_id: int,
1628        item_hash: int,
1629        character_id: int,
1630        member_type: typedefs.IntAnd[enums.MembershipType],
1631        *,
1632        stack_size: int = 1,
1633        vault: bool = False,
1634    ) -> None:
1635        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1636        payload = {
1637            "characterId": character_id,
1638            "membershipType": int(member_type),
1639            "itemId": item_id,
1640            "itemReferenceHash": item_hash,
1641            "stackSize": stack_size,
1642            "transferToVault": vault,
1643        }
1644        await self._request(
1645            RequestMethod.POST,
1646            "Destiny2/Actions/Items/PullFromPostmaster",
1647            json=payload,
1648            auth=access_token,
1649        )
1650
1651    async def fetch_fireteams(
1652        self,
1653        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1654        *,
1655        platform: typedefs.IntAnd[
1656            fireteams.FireteamPlatform
1657        ] = fireteams.FireteamPlatform.ANY,
1658        language: typing.Union[
1659            fireteams.FireteamLanguage, str
1660        ] = fireteams.FireteamLanguage.ALL,
1661        date_range: typedefs.IntAnd[
1662            fireteams.FireteamDate
1663        ] = fireteams.FireteamDate.ALL,
1664        page: int = 0,
1665        slots_filter: int = 0,
1666    ) -> typedefs.JSONObject:
1667        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1668        resp = await self._request(
1669            RequestMethod.GET,
1670            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1671        )
1672        assert isinstance(resp, dict)
1673        return resp
1674
1675    async def fetch_avaliable_clan_fireteams(
1676        self,
1677        access_token: str,
1678        group_id: int,
1679        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1680        *,
1681        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1682        language: typing.Union[fireteams.FireteamLanguage, str],
1683        date_range: typedefs.IntAnd[
1684            fireteams.FireteamDate
1685        ] = fireteams.FireteamDate.ALL,
1686        page: int = 0,
1687        public_only: bool = False,
1688        slots_filter: int = 0,
1689    ) -> typedefs.JSONObject:
1690        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1691        resp = await self._request(
1692            RequestMethod.GET,
1693            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1694            json={"langFilter": str(language)},
1695            auth=access_token,
1696        )
1697        assert isinstance(resp, dict)
1698        return resp
1699
1700    async def fetch_clan_fireteam(
1701        self, access_token: str, fireteam_id: int, group_id: int
1702    ) -> typedefs.JSONObject:
1703        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1704        resp = await self._request(
1705            RequestMethod.GET,
1706            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1707            auth=access_token,
1708        )
1709        assert isinstance(resp, dict)
1710        return resp
1711
1712    async def fetch_my_clan_fireteams(
1713        self,
1714        access_token: str,
1715        group_id: int,
1716        *,
1717        include_closed: bool = True,
1718        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1719        language: typing.Union[fireteams.FireteamLanguage, str],
1720        filtered: bool = True,
1721        page: int = 0,
1722    ) -> typedefs.JSONObject:
1723        payload = {"groupFilter": filtered, "langFilter": str(language)}
1724        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1725        resp = await self._request(
1726            RequestMethod.GET,
1727            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1728            json=payload,
1729            auth=access_token,
1730        )
1731        assert isinstance(resp, dict)
1732        return resp
1733
1734    async def fetch_private_clan_fireteams(
1735        self, access_token: str, group_id: int, /
1736    ) -> int:
1737        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1738        resp = await self._request(
1739            RequestMethod.GET,
1740            f"Fireteam/Clan/{group_id}/ActiveCount",
1741            auth=access_token,
1742        )
1743        assert isinstance(resp, int)
1744        return resp
1745
1746    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1747        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1748        resp = await self._request(
1749            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1750        )
1751        assert isinstance(resp, dict)
1752        return resp
1753
1754    async def search_entities(
1755        self, name: str, entity_type: str, *, page: int = 0
1756    ) -> typedefs.JSONObject:
1757        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1758        resp = await self._request(
1759            RequestMethod.GET,
1760            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1761            json={"page": page},
1762        )
1763        assert isinstance(resp, dict)
1764        return resp
1765
1766    async def fetch_unique_weapon_history(
1767        self,
1768        membership_id: int,
1769        character_id: int,
1770        membership_type: typedefs.IntAnd[enums.MembershipType],
1771    ) -> typedefs.JSONObject:
1772        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1773        resp = await self._request(
1774            RequestMethod.GET,
1775            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1776        )
1777        assert isinstance(resp, dict)
1778        return resp
1779
1780    async def fetch_item(
1781        self,
1782        member_id: int,
1783        item_id: int,
1784        membership_type: typedefs.IntAnd[enums.MembershipType],
1785        components: list[enums.ComponentType],
1786    ) -> typedefs.JSONObject:
1787        collector = _collect_components(components)
1788        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1789        resp = await self._request(
1790            RequestMethod.GET,
1791            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1792        )
1793        assert isinstance(resp, dict)
1794        return resp
1795
1796    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1797        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1798        resp = await self._request(
1799            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1800        )
1801        assert isinstance(resp, dict)
1802        return resp
1803
1804    async def fetch_available_locales(self) -> typedefs.JSONObject:
1805        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1806        resp = await self._request(
1807            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1808        )
1809        assert isinstance(resp, dict)
1810        return resp
1811
1812    async def fetch_common_settings(self) -> typedefs.JSONObject:
1813        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1814        resp = await self._request(RequestMethod.GET, "Settings")
1815        assert isinstance(resp, dict)
1816        return resp
1817
1818    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1819        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1820        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1821        assert isinstance(resp, dict)
1822        return resp
1823
1824    async def fetch_global_alerts(
1825        self, *, include_streaming: bool = False
1826    ) -> typedefs.JSONArray:
1827        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1828        resp = await self._request(
1829            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1830        )
1831        assert isinstance(resp, list)
1832        return resp
1833
1834    async def awainitialize_request(
1835        self,
1836        access_token: str,
1837        type: typing.Literal[0, 1],
1838        membership_type: typedefs.IntAnd[enums.MembershipType],
1839        /,
1840        *,
1841        affected_item_id: typing.Optional[int] = None,
1842        character_id: typing.Optional[int] = None,
1843    ) -> typedefs.JSONObject:
1844        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1845
1846        body = {"type": type, "membershipType": int(membership_type)}
1847
1848        if affected_item_id is not None:
1849            body["affectedItemId"] = affected_item_id
1850
1851        if character_id is not None:
1852            body["characterId"] = character_id
1853
1854        resp = await self._request(
1855            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1856        )
1857        assert isinstance(resp, dict)
1858        return resp
1859
1860    async def awaget_action_token(
1861        self, access_token: str, correlation_id: str, /
1862    ) -> typedefs.JSONObject:
1863        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1864        resp = await self._request(
1865            RequestMethod.POST,
1866            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1867            auth=access_token,
1868        )
1869        assert isinstance(resp, dict)
1870        return resp
1871
1872    async def awa_provide_authorization_result(
1873        self,
1874        access_token: str,
1875        selection: int,
1876        correlation_id: str,
1877        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1878    ) -> int:
1879        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1880
1881        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1882
1883        resp = await self._request(
1884            RequestMethod.POST,
1885            "Destiny2/Awa/AwaProvideAuthorizationResult",
1886            json=body,
1887            auth=access_token,
1888        )
1889        assert isinstance(resp, int)
1890        return resp
1891
1892    async def fetch_vendors(
1893        self,
1894        access_token: str,
1895        character_id: int,
1896        membership_id: int,
1897        membership_type: typedefs.IntAnd[enums.MembershipType],
1898        /,
1899        components: list[enums.ComponentType],
1900        filter: typing.Optional[int] = None,
1901    ) -> typedefs.JSONObject:
1902        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1903        components_ = _collect_components(components)
1904        route = (
1905            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1906            f"/Character/{character_id}/Vendors/?components={components_}"
1907        )
1908
1909        if filter is not None:
1910            route = route + f"&filter={filter}"
1911
1912        resp = await self._request(
1913            RequestMethod.GET,
1914            route,
1915            auth=access_token,
1916        )
1917        assert isinstance(resp, dict)
1918        return resp
1919
1920    async def fetch_vendor(
1921        self,
1922        access_token: str,
1923        character_id: int,
1924        membership_id: int,
1925        membership_type: typedefs.IntAnd[enums.MembershipType],
1926        vendor_hash: int,
1927        /,
1928        components: list[enums.ComponentType],
1929    ) -> typedefs.JSONObject:
1930        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1931        components_ = _collect_components(components)
1932        resp = await self._request(
1933            RequestMethod.GET,
1934            (
1935                f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}"
1936                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1937            ),
1938            auth=access_token,
1939        )
1940        assert isinstance(resp, dict)
1941        return resp
1942
1943    async def fetch_application_api_usage(
1944        self,
1945        access_token: str,
1946        application_id: int,
1947        /,
1948        *,
1949        start: typing.Optional[datetime.datetime] = None,
1950        end: typing.Optional[datetime.datetime] = None,
1951    ) -> typedefs.JSONObject:
1952
1953        end_date, start_date = time.parse_date_range(end, start)
1954        resp = await self._request(
1955            RequestMethod.GET,
1956            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1957            auth=access_token,
1958        )
1959        assert isinstance(resp, dict)
1960        return resp
1961
1962    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1963        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1964        assert isinstance(resp, list)
1965        return resp
1966
1967    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1968        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1969        assert isinstance(resp, dict)
1970        return resp
1971
1972    async def fetch_content_by_id(
1973        self, id: int, locale: str, /, *, head: bool = False
1974    ) -> typedefs.JSONObject:
1975        resp = await self._request(
1976            RequestMethod.GET,
1977            f"Content/GetContentById/{id}/{locale}/",
1978            json={"head": head},
1979        )
1980        assert isinstance(resp, dict)
1981        return resp
1982
1983    async def fetch_content_by_tag_and_type(
1984        self, locale: str, tag: str, type: str, *, head: bool = False
1985    ) -> typedefs.JSONObject:
1986        resp = await self._request(
1987            RequestMethod.GET,
1988            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1989            json={"head": head},
1990        )
1991        assert isinstance(resp, dict)
1992        return resp
1993
1994    async def search_content_with_text(
1995        self,
1996        locale: str,
1997        /,
1998        content_type: str,
1999        search_text: str,
2000        tag: str,
2001        *,
2002        page: undefined.UndefinedOr[int] = undefined.Undefined,
2003        source: undefined.UndefinedOr[str] = undefined.Undefined,
2004    ) -> typedefs.JSONObject:
2005
2006        body: typedefs.JSONObject = {}
2007
2008        body["ctype"] = content_type
2009        body["searchtext"] = search_text
2010        body["tag"] = tag
2011
2012        if page is not undefined.Undefined:
2013            body["currentpage"] = page
2014        else:
2015            body["currentpage"] = 1
2016
2017        if source is not undefined.Undefined:
2018            body["source"] = source
2019        else:
2020            source = ""
2021        resp = await self._request(
2022            RequestMethod.GET, f"Content/Search/{locale}/", json=body
2023        )
2024        assert isinstance(resp, dict)
2025        return resp
2026
2027    async def search_content_by_tag_and_type(
2028        self,
2029        locale: str,
2030        tag: str,
2031        type: str,
2032        *,
2033        page: undefined.UndefinedOr[int] = undefined.Undefined,
2034    ) -> typedefs.JSONObject:
2035        body: typedefs.JSONObject = {}
2036        body["currentpage"] = 1 if page is undefined.Undefined else page
2037        resp = await self._request(
2038            RequestMethod.GET,
2039            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
2040            json=body,
2041        )
2042        assert isinstance(resp, dict)
2043        return resp
2044
2045    async def search_help_articles(
2046        self, text: str, size: str, /
2047    ) -> typedefs.JSONObject:
2048        resp = await self._request(
2049            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
2050        )
2051        assert isinstance(resp, dict)
2052        return resp
2053
2054    async def fetch_topics_page(
2055        self,
2056        category_filter: int,
2057        group: int,
2058        date_filter: int,
2059        sort: typing.Union[str, bytes],
2060        *,
2061        page: undefined.UndefinedOr[int] = undefined.Undefined,
2062        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2063        tag_filter: undefined.UndefinedOr[str] = undefined.Undefined,
2064    ) -> typedefs.JSONObject:
2065
2066        body: typedefs.JSONObject = {}
2067        if locales is not undefined.Undefined:
2068            body["locales"] = ",".join(str(locales))
2069        else:
2070            body["locales"] = ",".join([])
2071
2072        if tag_filter is not undefined.Undefined:
2073            body["tagstring"] = tag_filter
2074        else:
2075            body["tagstring"] = ""
2076
2077        page = 0 if page is not undefined.Undefined else page
2078
2079        resp = await self._request(
2080            RequestMethod.GET,
2081            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
2082            json=body,
2083        )
2084        assert isinstance(resp, dict)
2085        return resp
2086
2087    async def fetch_core_topics_page(
2088        self,
2089        category_filter: int,
2090        date_filter: int,
2091        sort: typing.Union[str, bytes],
2092        *,
2093        page: undefined.UndefinedOr[int] = undefined.Undefined,
2094        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2095    ) -> typedefs.JSONObject:
2096        body: typedefs.JSONObject = {}
2097
2098        if locales is not undefined.Undefined:
2099            body["locales"] = ",".join(str(locales))
2100        else:
2101            body["locales"] = ",".join([])
2102
2103        resp = await self._request(
2104            RequestMethod.GET,
2105            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}"
2106            f"/{sort!s}/{date_filter}/{category_filter}/",
2107            json=body,
2108        )
2109        assert isinstance(resp, dict)
2110        return resp
2111
2112    async def fetch_posts_threaded_page(
2113        self,
2114        parent_post: bool,
2115        page: int,
2116        page_size: int,
2117        parent_post_id: int,
2118        reply_size: int,
2119        root_thread_mode: bool,
2120        sort_mode: int,
2121        show_banned: typing.Optional[str] = None,
2122    ) -> typedefs.JSONObject:
2123        resp = await self._request(
2124            RequestMethod.GET,
2125            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2126            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2127            json={"showbanned": show_banned},
2128        )
2129        assert isinstance(resp, dict)
2130        return resp
2131
2132    async def fetch_posts_threaded_page_from_child(
2133        self,
2134        child_id: bool,
2135        page: int,
2136        page_size: int,
2137        reply_size: int,
2138        root_thread_mode: bool,
2139        sort_mode: int,
2140        show_banned: typing.Optional[str] = None,
2141    ) -> typedefs.JSONObject:
2142        resp = await self._request(
2143            RequestMethod.GET,
2144            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2145            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2146            json={"showbanned": show_banned},
2147        )
2148        assert isinstance(resp, dict)
2149        return resp
2150
2151    async def fetch_post_and_parent(
2152        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2153    ) -> typedefs.JSONObject:
2154        resp = await self._request(
2155            RequestMethod.GET,
2156            f"Forum/GetPostAndParent/{child_id}/",
2157            json={"showbanned": show_banned},
2158        )
2159        assert isinstance(resp, dict)
2160        return resp
2161
2162    async def fetch_posts_and_parent_awaiting(
2163        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2164    ) -> typedefs.JSONObject:
2165        resp = await self._request(
2166            RequestMethod.GET,
2167            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2168            json={"showbanned": show_banned},
2169        )
2170        assert isinstance(resp, dict)
2171        return resp
2172
2173    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2174        resp = await self._request(
2175            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2176        )
2177        assert isinstance(resp, int)
2178        return resp
2179
2180    async def fetch_forum_tag_suggestions(
2181        self, partial_tag: str, /
2182    ) -> typedefs.JSONObject:
2183        resp = await self._request(
2184            RequestMethod.GET,
2185            "Forum/GetForumTagSuggestions/",
2186            json={"partialtag": partial_tag},
2187        )
2188        assert isinstance(resp, dict)
2189        return resp
2190
2191    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2192        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2193        assert isinstance(resp, dict)
2194        return resp
2195
2196    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2197        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2198        assert isinstance(resp, list)
2199        return resp
2200
2201    async def fetch_recommended_groups(
2202        self,
2203        accecss_token: str,
2204        /,
2205        *,
2206        date_range: int = 0,
2207        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
2208    ) -> typedefs.JSONArray:
2209        resp = await self._request(
2210            RequestMethod.POST,
2211            f"GroupV2/Recommended/{int(group_type)}/{date_range}/",
2212            auth=accecss_token,
2213        )
2214        assert isinstance(resp, list)
2215        return resp
2216
2217    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2218        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2219        assert isinstance(resp, dict)
2220        return resp
2221
2222    async def fetch_user_clan_invite_setting(
2223        self,
2224        access_token: str,
2225        /,
2226        membership_type: typedefs.IntAnd[enums.MembershipType],
2227    ) -> bool:
2228        resp = await self._request(
2229            RequestMethod.GET,
2230            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2231            auth=access_token,
2232        )
2233        assert isinstance(resp, bool)
2234        return resp
2235
2236    async def fetch_banned_group_members(
2237        self, access_token: str, group_id: int, /, *, page: int = 1
2238    ) -> typedefs.JSONObject:
2239        resp = await self._request(
2240            RequestMethod.GET,
2241            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2242            auth=access_token,
2243        )
2244        assert isinstance(resp, dict)
2245        return resp
2246
2247    async def fetch_pending_group_memberships(
2248        self, access_token: str, group_id: int, /, *, current_page: int = 1
2249    ) -> typedefs.JSONObject:
2250        resp = await self._request(
2251            RequestMethod.GET,
2252            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2253            auth=access_token,
2254        )
2255        assert isinstance(resp, dict)
2256        return resp
2257
2258    async def fetch_invited_group_memberships(
2259        self, access_token: str, group_id: int, /, *, current_page: int = 1
2260    ) -> typedefs.JSONObject:
2261        resp = await self._request(
2262            RequestMethod.GET,
2263            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2264            auth=access_token,
2265        )
2266        assert isinstance(resp, dict)
2267        return resp
2268
2269    async def invite_member_to_group(
2270        self,
2271        access_token: str,
2272        /,
2273        group_id: int,
2274        membership_id: int,
2275        membership_type: typedefs.IntAnd[enums.MembershipType],
2276        *,
2277        message: undefined.UndefinedOr[str] = undefined.Undefined,
2278    ) -> typedefs.JSONObject:
2279        resp = await self._request(
2280            RequestMethod.POST,
2281            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2282            auth=access_token,
2283            json={"message": str(message)},
2284        )
2285        assert isinstance(resp, dict)
2286        return resp
2287
2288    async def cancel_group_member_invite(
2289        self,
2290        access_token: str,
2291        /,
2292        group_id: int,
2293        membership_id: int,
2294        membership_type: typedefs.IntAnd[enums.MembershipType],
2295    ) -> typedefs.JSONObject:
2296        resp = await self._request(
2297            RequestMethod.POST,
2298            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2299            auth=access_token,
2300        )
2301        assert isinstance(resp, dict)
2302        return resp
2303
2304    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2305        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2306        assert isinstance(resp, dict)
2307        return resp
2308
2309    async def fetch_historical_stats(
2310        self,
2311        character_id: int,
2312        membership_id: int,
2313        membership_type: typedefs.IntAnd[enums.MembershipType],
2314        day_start: datetime.datetime,
2315        day_end: datetime.datetime,
2316        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2317        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2318        *,
2319        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2320    ) -> typedefs.JSONObject:
2321
2322        end, start = time.parse_date_range(day_end, day_start)
2323        resp = await self._request(
2324            RequestMethod.GET,
2325            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2326            json={
2327                "dayend": end,
2328                "daystart": start,
2329                "groups": [str(int(group)) for group in groups],
2330                "modes": [str(int(mode)) for mode in modes],
2331                "periodType": int(period_type),
2332            },
2333        )
2334        assert isinstance(resp, dict)
2335        return resp
2336
2337    async def fetch_historical_stats_for_account(
2338        self,
2339        membership_id: int,
2340        membership_type: typedefs.IntAnd[enums.MembershipType],
2341        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2342    ) -> typedefs.JSONObject:
2343        resp = await self._request(
2344            RequestMethod.GET,
2345            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2346            json={"groups": [str(int(group)) for group in groups]},
2347        )
2348        assert isinstance(resp, dict)
2349        return resp
2350
2351    async def fetch_aggregated_activity_stats(
2352        self,
2353        character_id: int,
2354        membership_id: int,
2355        membership_type: typedefs.IntAnd[enums.MembershipType],
2356        /,
2357    ) -> typedefs.JSONObject:
2358        resp = await self._request(
2359            RequestMethod.GET,
2360            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2361            f"Character/{character_id}/Stats/AggregateActivityStats/",
2362        )
2363        assert isinstance(resp, dict)
2364        return resp

A RESTful client implementation for Bungie's API.

This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.

This client is also used within aiobungie.Client which deserialize those returned JSON objects using the factory into Pythonic data classes objects which provide Python functionality.

Example
import aiobungie

async def main():
    async with aiobungie.RESTClient("TOKEN") as rest_client:
        req = await rest_client.fetch_clan_members(4389205)
        clan_members = req['results']
        for member in clan_members:
            for k, v in member['destinyUserInfo'].items():
                print(k, v)
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • max_ratelimit_retries (int): The max retries number to retry if the request hit a 429 status code. Defaults to 3.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
RESTClient( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, max_retries: int = 4, max_ratelimit_retries: int = 3, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
425    def __init__(
426        self,
427        token: str,
428        /,
429        client_secret: typing.Optional[str] = None,
430        client_id: typing.Optional[int] = None,
431        *,
432        max_retries: int = 4,
433        max_ratelimit_retries: int = 3,
434        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
435    ) -> None:
436        self._session: typing.Optional[_Session] = None
437        self._lock: typing.Optional[asyncio.Lock] = None
438        self._client_secret = client_secret
439        self._client_id = client_id
440        self._token: str = token
441        self._max_retries = max_retries
442        self._max_rate_limit_retries = max_ratelimit_retries
443        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
444
445        self._set_debug_level(enable_debugging)
client_id: Optional[int]

Return the client id of this REST client if provided, Otherwise None.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

This mapping is useful for storing any kind of data that the user may need.

Example
import aiobungie

client = aiobungie.RESTClient(…)

async with client:
    # Fetch auth tokens and store them
    client.metadata["tokens"] = await client.fetch_access_token("code")

# Some other time.
async with client:
    # Retrieve the tokens
    tokens: aiobungie.OAuth2Response = client.metadata["tokens"]

    # Use them to fetch your user.
    user = await client.fetch_current_user_memberships(tokens.access_token)
is_alive: bool

Returns True if the REST client is alive and False otherwise.

@typing.final
async def close(self) -> None:
459    @typing.final
460    async def close(self) -> None:
461        session = self._get_session()
462        await session.close()
463        self._session = None

Close this REST client session if it was acquired.

This method is automatically called when using async with contextmanager.

Raises
  • RuntimeError: If the client is already closed.
@typing.final
def open(self) -> None:
465    @typing.final
466    def open(self) -> None:
467        """Open a new client session. This is called internally with contextmanager usage."""
468        if self.is_alive:
469            raise RuntimeError("Cannot open a new session while it's already open.")
470
471        self._session = _Session.create(
472            owner=False,
473            raise_status=False,
474            connect=None,
475            socket_read=None,
476            socket_connect=None,
477        )

Open a new client session. This is called internally with contextmanager usage.

@typing.final
def enable_debugging( self, level: Union[Literal['TRACE'], bool, int] = False, file: Union[pathlib.Path, str, NoneType] = None, /) -> None:
479    @typing.final
480    def enable_debugging(
481        self,
482        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
483        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
484        /,
485    ) -> None:
486        self._set_debug_level(level, file)

Enables debugging for the REST calls.

Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
Parameters
  • level (str | bool | int): The level of debugging to enable.
  • file (pathlib.Path | str | None): The file path to write the debug logs to. If provided.
@typing.final
async def static_request( self, method: Union[aiobungie.RequestMethod, str], path: str, *, auth: Optional[str] = None, json: Optional[dict[str, Any]] = None) -> Union[dict[str, Any], list[Any], bytes, int, bool, NoneType]:
488    @typing.final
489    async def static_request(
490        self,
491        method: typing.Union[RequestMethod, str],
492        path: str,
493        *,
494        auth: typing.Optional[str] = None,
495        json: typing.Optional[dict[str, typing.Any]] = None,
496    ) -> ResponseSig:
497        return await self._request(method, path, auth=auth, json=json)

Perform an HTTP request given a valid Bungie endpoint.

Parameters
  • method (aiobungie.RequestMethod | str): The request method, This may be GET, POST, PUT, etc.
  • path (str): The Bungie endpoint or path. A path must look something like this Destiny2/3/Profile/46111239123/...
  • auth (str | None): An optional bearer token for methods that requires OAuth2 Authorization header.
  • json (dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
  • aiobungie.rest.ResponseSig: The response payload.
@typing.final
def build_oauth2_url(self, client_id: Optional[int] = None) -> Optional[str]:
499    @typing.final
500    def build_oauth2_url(
501        self, client_id: typing.Optional[int] = None
502    ) -> typing.Optional[str]:
503        client_id = client_id or self._client_id
504        if client_id is None:
505            return None
506
507        return url.OAUTH2_EP_BUILDER.format(
508            oauth_endpoint=url.OAUTH_EP,
509            client_id=client_id,
510            uuid=_uuid(),
511        )

Builds an OAuth2 URL using the provided user REST/Base client secret/id.

Parameters
  • client_id (int | None): An optional client id to provide, If left None it will roll back to the id passed to the RESTClient, If both is None this method will return None.
Returns
  • str | None: If the client id was provided as a parameter or provided in aiobungie.RESTClient, A complete URL will be returned. Otherwise None will be returned.
async def fetch_oauth2_tokens(self, code: str, /) -> aiobungie.builders.OAuth2Response:
738    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
739
740        if not isinstance(self._client_id, int):
741            raise TypeError(
742                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
743            )
744
745        if not isinstance(self._client_secret, str):
746            raise TypeError(
747                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
748            )
749
750        headers = {
751            "client_secret": self._client_secret,
752        }
753
754        data = (
755            f"grant_type=authorization_code&code={code}"
756            f"&client_id={self._client_id}&client_secret={self._client_secret}"
757        )
758
759        response = await self._request(
760            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
761        )
762        assert isinstance(response, dict)
763        return builders.OAuth2Response.build_response(response)

Makes a POST request and fetch the OAuth2 access_token and refresh token.

Parameters
  • code (str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
Raises
async def refresh_access_token(self, refresh_token: str, /) -> aiobungie.builders.OAuth2Response:
765    async def refresh_access_token(
766        self, refresh_token: str, /
767    ) -> builders.OAuth2Response:
768        if not isinstance(self._client_id, int):
769            raise TypeError(
770                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
771            )
772
773        if not isinstance(self._client_secret, str):
774            raise TypeError(
775                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
776            )
777
778        data = {
779            "grant_type": "refresh_token",
780            "refresh_token": refresh_token,
781            "client_id": self._client_id,
782            "client_secret": self._client_secret,
783            "Content-Type": "application/x-www-form-urlencoded",
784        }
785
786        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
787        assert isinstance(response, dict)
788        return builders.OAuth2Response.build_response(response)

Refresh OAuth2 access token given its refresh token.

Parameters
  • refresh_token (str): The refresh token.
Returns
async def fetch_bungie_user(self, id: int) -> dict[str, typing.Any]:
790    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
791        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
792        resp = await self._request(
793            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
794        )
795        assert isinstance(resp, dict)
796        return resp

Fetch a Bungie user by their id.

Parameters
  • id (int): The user id.
Returns
Raises
async def fetch_user_themes(self) -> list[typing.Any]:
798    async def fetch_user_themes(self) -> typedefs.JSONArray:
799        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
800        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
801        assert isinstance(resp, list)
802        return resp

Fetch all available user themes.

Returns
async def fetch_membership_from_id( self, id: int, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>, /) -> dict[str, typing.Any]:
804    async def fetch_membership_from_id(
805        self,
806        id: int,
807        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
808        /,
809    ) -> typedefs.JSONObject:
810        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
811        resp = await self._request(
812            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
813        )
814        assert isinstance(resp, dict)
815        return resp

Fetch Bungie user's memberships from their id.

Parameters
Returns
Raises
async def fetch_player( self, name: str, code: int, type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, /) -> list[typing.Any]:
817    async def fetch_player(
818        self,
819        name: str,
820        code: int,
821        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
822        /,
823    ) -> typedefs.JSONArray:
824        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
825        resp = await self._request(
826            RequestMethod.POST,
827            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
828            json={"displayName": name, "displayNameCode": code},
829        )
830        assert isinstance(resp, list)
831        return resp

Fetch a Destiny 2 Player.

Parameters
Returns
Raises
async def search_users(self, name: str, /) -> dict[str, typing.Any]:
833    async def search_users(self, name: str, /) -> typedefs.JSONObject:
834        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
835        resp = await self._request(
836            RequestMethod.POST,
837            "User/Search/GlobalName/0",
838            json={"displayNamePrefix": name},
839        )
840        assert isinstance(resp, dict)
841        return resp

Search for users by their global name and return all users who share this name.

Parameters
  • name (str): The user name.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> dict[str, typing.Any]:
843    async def fetch_clan_from_id(
844        self, id: int, /, access_token: typing.Optional[str] = None
845    ) -> typedefs.JSONObject:
846        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
847        resp = await self._request(
848            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
849        )
850        assert isinstance(resp, dict)
851        return resp

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Other Parameters
  • access_token (typing.Optional[str]): An optional access token to make the request with.

    If the token was bound to a member of the clan, This field aiobungie.crates.Clan.current_user_membership will be available and will return the membership of the user who made this request.

Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
853    async def fetch_clan(
854        self,
855        name: str,
856        /,
857        access_token: typing.Optional[str] = None,
858        *,
859        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
860    ) -> typedefs.JSONObject:
861        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
862        resp = await self._request(
863            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
864        )
865        assert isinstance(resp, dict)
866        return resp

Fetch a Clan by its name. This method will return the first clan found with given name name.

Parameters
  • name (str): The clan name.
Other Parameters
Returns
Raises
async def fetch_clan_admins(self, clan_id: int, /) -> dict[str, typing.Any]:
868    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
869        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
870        resp = await self._request(
871            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
872        )
873        assert isinstance(resp, dict)
874        return resp

Fetch the admins and founder members of the clan.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_clan_conversations(self, clan_id: int, /) -> list[typing.Any]:
876    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
877        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
878        resp = await self._request(
879            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
880        )
881        assert isinstance(resp, list)
882        return resp

Fetch a clan's conversations.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_application(self, appid: int, /) -> dict[str, typing.Any]:
884    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
885        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
886        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
887        assert isinstance(resp, dict)
888        return resp

Fetch a Bungie Application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_character( self, member_id: int, membership_type: Union[int, aiobungie.MembershipType], character_id: int, components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
890    async def fetch_character(
891        self,
892        member_id: int,
893        membership_type: typedefs.IntAnd[enums.MembershipType],
894        character_id: int,
895        components: list[enums.ComponentType],
896        auth: typing.Optional[str] = None,
897    ) -> typedefs.JSONObject:
898        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
899        collector = _collect_components(components)
900        response = await self._request(
901            RequestMethod.GET,
902            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
903            f"Character/{character_id}/?components={collector}",
904            auth=auth,
905        )
906        assert isinstance(response, dict)
907        return response

Fetch a Destiny 2 player's characters.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, aiobungie.GameMode], membership_type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, *, page: int = 0, limit: int = 1) -> dict[str, typing.Any]:
909    async def fetch_activities(
910        self,
911        member_id: int,
912        character_id: int,
913        mode: typedefs.IntAnd[enums.GameMode],
914        membership_type: typedefs.IntAnd[
915            enums.MembershipType
916        ] = enums.MembershipType.ALL,
917        *,
918        page: int = 0,
919        limit: int = 1,
920    ) -> typedefs.JSONObject:
921        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
922        resp = await self._request(
923            RequestMethod.GET,
924            f"Destiny2/{int(membership_type)}/Account/"
925            f"{member_id}/Character/{character_id}/Stats/Activities"
926            f"/?mode={int(mode)}&count={limit}&page={page}",
927        )
928        assert isinstance(resp, dict)
929        return resp

Fetch a Destiny 2 activity for the specified user id and character.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
Returns
Raises
async def fetch_vendor_sales(self) -> dict[str, typing.Any]:
931    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
932        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
933        resp = await self._request(
934            RequestMethod.GET,
935            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
936        )
937        assert isinstance(resp, dict)
938        return resp
async def fetch_profile( self, membership_id: int, type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
940    async def fetch_profile(
941        self,
942        membership_id: int,
943        type: typedefs.IntAnd[enums.MembershipType],
944        components: list[enums.ComponentType],
945        auth: typing.Optional[str] = None,
946    ) -> typedefs.JSONObject:
947        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
948        collector = _collect_components(components)
949        response = await self._request(
950            RequestMethod.GET,
951            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
952            auth=auth,
953        )
954        assert isinstance(response, dict)
955        return response

Fetch a bungie profile.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_entity(self, type: str, hash: int) -> dict[str, typing.Any]:
957    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
958        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
959        response = await self._request(
960            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
961        )
962        assert isinstance(response, dict)
963        return response

Fetch a Destiny definition item given its type and hash.

Parameters
  • type (str): Entity's type definition.
  • hash (int): Entity's hash.
Returns
async def fetch_inventory_item(self, hash: int, /) -> dict[str, typing.Any]:
965    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
966        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
967        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
968        assert isinstance(resp, dict)
969        return resp

Fetch a Destiny inventory item entity given a its hash.

Parameters
  • hash (int): Entity's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> dict[str, typing.Any]:
971    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
972        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
973        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
974        assert isinstance(resp, dict)
975        return resp

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
977    async def fetch_groups_for_member(
978        self,
979        member_id: int,
980        member_type: typedefs.IntAnd[enums.MembershipType],
981        /,
982        *,
983        filter: int = 0,
984        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
985    ) -> typedefs.JSONObject:
986        resp = await self._request(
987            RequestMethod.GET,
988            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
989        )
990        assert isinstance(resp, dict)
991        return resp

Fetch the information about the groups for a member.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
 993    async def fetch_potential_groups_for_member(
 994        self,
 995        member_id: int,
 996        member_type: typedefs.IntAnd[enums.MembershipType],
 997        /,
 998        *,
 999        filter: int = 0,
1000        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
1001    ) -> typedefs.JSONObject:
1002        resp = await self._request(
1003            RequestMethod.GET,
1004            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
1005        )
1006        assert isinstance(resp, dict)
1007        return resp

Get information about the groups that a given member has applied to or been invited to.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> dict[str, typing.Any]:
1009    async def fetch_clan_members(
1010        self,
1011        clan_id: int,
1012        /,
1013        *,
1014        name: typing.Optional[str] = None,
1015        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
1016    ) -> typedefs.JSONObject:
1017        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1018        resp = await self._request(
1019            RequestMethod.GET,
1020            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
1021        )
1022        assert isinstance(resp, dict)
1023        return resp

Fetch all Bungie Clan members.

Parameters
  • clan_id (builsins.int): The clans id
Other Parameters
Returns
Raises
async def fetch_hardlinked_credentials( self, credential: int, type: Union[int, aiobungie.CredentialType] = <CredentialType.STEAMID: 12>, /) -> dict[str, typing.Any]:
1025    async def fetch_hardlinked_credentials(
1026        self,
1027        credential: int,
1028        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
1029        /,
1030    ) -> typedefs.JSONObject:
1031        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1032        resp = await self._request(
1033            RequestMethod.GET,
1034            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
1035        )
1036        assert isinstance(resp, dict)
1037        return resp

Gets any hard linked membership given a credential.

Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
Returns
async def fetch_user_credentials(self, access_token: str, membership_id: int, /) -> list[typing.Any]:
1039    async def fetch_user_credentials(
1040        self, access_token: str, membership_id: int, /
1041    ) -> typedefs.JSONArray:
1042        resp = await self._request(
1043            RequestMethod.GET,
1044            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
1045            auth=access_token,
1046        )
1047        assert isinstance(resp, list)
1048        return resp

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def insert_socket_plug( self, action_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1050    async def insert_socket_plug(
1051        self,
1052        action_token: str,
1053        /,
1054        instance_id: int,
1055        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1056        character_id: int,
1057        membership_type: typedefs.IntAnd[enums.MembershipType],
1058    ) -> typedefs.JSONObject:
1059
1060        if isinstance(plug, builders.PlugSocketBuilder):
1061            plug = plug.collect()
1062
1063        body = {
1064            "actionToken": action_token,
1065            "itemInstanceId": instance_id,
1066            "plug": plug,
1067            "characterId": character_id,
1068            "membershipType": int(membership_type),
1069        }
1070        resp = await self._request(
1071            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
1072        )
1073        assert isinstance(resp, dict)
1074        return resp

Insert a plug into a socketed item.

OAuth2: AdvancedWriteActions scope is required

Parameters
  • action_token (str): Action token provided by the AwaGetActionToken API call.
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def insert_socket_plug_free( self, access_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1076    async def insert_socket_plug_free(
1077        self,
1078        access_token: str,
1079        /,
1080        instance_id: int,
1081        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1082        character_id: int,
1083        membership_type: typedefs.IntAnd[enums.MembershipType],
1084    ) -> typedefs.JSONObject:
1085
1086        if isinstance(plug, builders.PlugSocketBuilder):
1087            plug = plug.collect()
1088
1089        body = {
1090            "itemInstanceId": instance_id,
1091            "plug": plug,
1092            "characterId": character_id,
1093            "membershipType": int(membership_type),
1094        }
1095        resp = await self._request(
1096            RequestMethod.POST,
1097            "Destiny2/Actions/Items/InsertSocketPlugFree",
1098            json=body,
1099            auth=access_token,
1100        )
1101        assert isinstance(resp, dict)
1102        return resp

Insert a plug into a socketed item. This doesn't require an Action token.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def set_item_lock_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> int:
1104    async def set_item_lock_state(
1105        self,
1106        access_token: str,
1107        state: bool,
1108        /,
1109        item_id: int,
1110        character_id: int,
1111        membership_type: typedefs.IntAnd[enums.MembershipType],
1112    ) -> int:
1113        body = {
1114            "state": state,
1115            "itemId": item_id,
1116            "characterId": character_id,
1117            "membership_type": int(membership_type),
1118        }
1119        response = await self._request(
1120            RequestMethod.POST,
1121            "Destiny2/Actions/Items/SetLockState",
1122            json=body,
1123            auth=access_token,
1124        )
1125        assert isinstance(response, int)
1126        return response

Set the Lock State for an instanced item.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def set_quest_track_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> int:
1128    async def set_quest_track_state(
1129        self,
1130        access_token: str,
1131        state: bool,
1132        /,
1133        item_id: int,
1134        character_id: int,
1135        membership_type: typedefs.IntAnd[enums.MembershipType],
1136    ) -> int:
1137        body = {
1138            "state": state,
1139            "itemId": item_id,
1140            "characterId": character_id,
1141            "membership_type": int(membership_type),
1142        }
1143        response = await self._request(
1144            RequestMethod.POST,
1145            "Destiny2/Actions/Items/SetTrackedState",
1146            json=body,
1147            auth=access_token,
1148        )
1149        assert isinstance(response, int)
1150        return response

Set the Tracking State for an instanced Quest or Bounty.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def fetch_manifest_path(self) -> dict[str, typing.Any]:
1152    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1153        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1154        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1155        assert isinstance(path, dict)
1156        return path

Fetch the manifest JSON paths.

Returns
  • typedefs.JSONObject: The manifest JSON paths.
async def read_manifest_bytes(self, language: str = 'en', /) -> bytes:
1158    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1159        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1160        _ensure_manifest_language(language)
1161
1162        content = await self.fetch_manifest_path()
1163        resp = await self._request(
1164            RequestMethod.GET,
1165            content["mobileWorldContentPaths"][language],
1166            unwrapping="read",
1167            base=True,
1168        )
1169        assert isinstance(resp, bytes)
1170        return resp

Read raw manifest SQLite database bytes response.

This method can be used to write the bytes to zipped file and then extract it to get the manifest content.

Parameters
  • language (str): The manifest database language bytes to get.
Returns
  • bytes: The bytes to read and write the manifest database.
async def download_manifest( self, language: str = 'en', name: str = 'manifest', path: Union[pathlib.Path, str] = '.', *, force: bool = False) -> None:
1172    async def download_manifest(
1173        self,
1174        language: str = "en",
1175        name: str = "manifest",
1176        path: typing.Union[pathlib.Path, str] = ".",
1177        *,
1178        force: bool = False,
1179    ) -> None:
1180        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1181        complete_path = _get_path(name, path, sql=True)
1182
1183        if complete_path.exists() and force:
1184            if force:
1185                _LOG.info(
1186                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1187                )
1188                complete_path.unlink(missing_ok=True)
1189
1190                return await self.download_manifest(language, name, path, force=force)
1191
1192            else:
1193                raise FileExistsError(
1194                    "Manifest file already exists, "
1195                    "To force download, set the `force` parameter to `True`."
1196                )
1197
1198        _LOG.info(f"Downloading manifest. Location: {complete_path!s}")
1199        data_bytes = await self.read_manifest_bytes(language)
1200        await asyncio.get_running_loop().run_in_executor(
1201            None, _write_sqlite_bytes, data_bytes, path, name
1202        )

A helper method to download the manifest.

Note

This method downloads the sqlite database and not JSON. Use RESTInterface.download_json_manifest for the JSON version.

Parameters
  • language (str): The manifest language to download, Default is english.
  • path (str | pathlib.Path): The path to save the manifest sqlite database. Example "D:/", Default is the current directory.
  • name (str): The manifest database file name. Default is manifest
  • force (bool): Whether to force the download. Default is False. However if set to true the old file will get removed and a new one will being to download.
Returns
  • None
Raises
  • FileNotFoundError: If the manifest file exists and force is False.
  • ValueError: If the provided language was not recognized.
async def download_json_manifest( self, file_name: str = 'manifest', path: Union[str, pathlib.Path] = '.', language: str = 'en') -> None:
1204    async def download_json_manifest(
1205        self,
1206        file_name: str = "manifest",
1207        path: typing.Union[str, pathlib.Path] = ".",
1208        language: str = "en",
1209    ) -> None:
1210        _ensure_manifest_language(language)
1211
1212        _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...")
1213
1214        content = await self.fetch_manifest_path()
1215        json_bytes = await self._request(
1216            RequestMethod.GET,
1217            content["jsonWorldContentPaths"][language],
1218            unwrapping="read",
1219            base=True,
1220        )
1221
1222        await asyncio.get_running_loop().run_in_executor(
1223            None, _write_json_bytes, json_bytes, file_name, path
1224        )
1225        _LOG.info("Finished downloading manifest JSON.")

Download the Bungie manifest json file.

Parameters
  • file_name (str): The file name to save the manifest json file. Default is manifest.
  • path (str | pathlib.Path): The path to save the manifest json file. Default is the current directory. Example "D:/"
  • language (str): The manifest database language bytes to get. Default is English.
async def fetch_manifest_version(self) -> str:
1227    async def fetch_manifest_version(self) -> str:
1228        return typing.cast(str, (await self.fetch_manifest_path())["version"])

Fetch the manifest version.

Returns
  • str: The manifest version.
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, all: bool = False) -> dict[str, typing.Any]:
1230    async def fetch_linked_profiles(
1231        self,
1232        member_id: int,
1233        member_type: typedefs.IntAnd[enums.MembershipType],
1234        /,
1235        *,
1236        all: bool = False,
1237    ) -> typedefs.JSONObject:
1238        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1239        resp = await self._request(
1240            RequestMethod.GET,
1241            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1242        )
1243        assert isinstance(resp, dict)
1244        return resp

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether thry're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
async def fetch_clan_banners(self) -> dict[str, typing.Any]:
1246    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1247        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1248        resp = await self._request(
1249            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1250        )
1251        assert isinstance(resp, dict)
1252        return resp

Fetch the values of the clan banners.

Returns
async def fetch_public_milestones(self) -> dict[str, typing.Any]:
1254    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1255        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1256        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1257        assert isinstance(resp, dict)
1258        return resp

Fetch the available milestones.

Returns
async def fetch_public_milestone_content(self, milestone_hash: int, /) -> dict[str, typing.Any]:
1260    async def fetch_public_milestone_content(
1261        self, milestone_hash: int, /
1262    ) -> typedefs.JSONObject:
1263        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1264        resp = await self._request(
1265            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1266        )
1267        assert isinstance(resp, dict)
1268        return resp

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
async def fetch_current_user_memberships(self, access_token: str, /) -> dict[str, typing.Any]:
1270    async def fetch_current_user_memberships(
1271        self, access_token: str, /
1272    ) -> typedefs.JSONObject:
1273        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1274        resp = await self._request(
1275            RequestMethod.GET,
1276            "User/GetMembershipsForCurrentUser/",
1277            auth=access_token,
1278        )
1279        assert isinstance(resp, dict)
1280        return resp

Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.

This requires OAuth2 scope enabled and the valid Bearer access_token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def equip_item( self, access_token: str, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1282    async def equip_item(
1283        self,
1284        access_token: str,
1285        /,
1286        item_id: int,
1287        character_id: int,
1288        membership_type: typedefs.IntAnd[enums.MembershipType],
1289    ) -> None:
1290        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1291        payload = {
1292            "itemId": item_id,
1293            "characterId": character_id,
1294            "membershipType": int(membership_type),
1295        }
1296
1297        await self._request(
1298            RequestMethod.POST,
1299            "Destiny2/Actions/Items/EquipItem/",
1300            json=payload,
1301            auth=access_token,
1302        )

Equip an item to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item id.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def equip_items( self, access_token: str, /, item_ids: list[int], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1304    async def equip_items(
1305        self,
1306        access_token: str,
1307        /,
1308        item_ids: list[int],
1309        character_id: int,
1310        membership_type: typedefs.IntAnd[enums.MembershipType],
1311    ) -> None:
1312        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1313        payload = {
1314            "itemIds": item_ids,
1315            "characterId": character_id,
1316            "membershipType": int(membership_type),
1317        }
1318        await self._request(
1319            RequestMethod.POST,
1320            "Destiny2/Actions/Items/EquipItems/",
1321            json=payload,
1322            auth=access_token,
1323        )

Equip multiple items to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_ids (list[int]): A list of item ids.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def ban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], *, length: int = 0, comment: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1325    async def ban_clan_member(
1326        self,
1327        access_token: str,
1328        /,
1329        group_id: int,
1330        membership_id: int,
1331        membership_type: typedefs.IntAnd[enums.MembershipType],
1332        *,
1333        length: int = 0,
1334        comment: undefined.UndefinedOr[str] = undefined.Undefined,
1335    ) -> None:
1336        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1337        payload = {"comment": str(comment), "length": length}
1338        await self._request(
1339            RequestMethod.POST,
1340            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1341            json=payload,
1342            auth=access_token,
1343        )

Bans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to ban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
  • length (int): An optional ban length.
  • comment (aiobungie.UndefinedOr[str]): An optional comment to this ban. Default is UNDEFINED
async def unban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1345    async def unban_clan_member(
1346        self,
1347        access_token: str,
1348        /,
1349        group_id: int,
1350        membership_id: int,
1351        membership_type: typedefs.IntAnd[enums.MembershipType],
1352    ) -> None:
1353        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1354        await self._request(
1355            RequestMethod.POST,
1356            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1357            auth=access_token,
1358        )

Unbans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to unban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1360    async def kick_clan_member(
1361        self,
1362        access_token: str,
1363        /,
1364        group_id: int,
1365        membership_id: int,
1366        membership_type: typedefs.IntAnd[enums.MembershipType],
1367    ) -> typedefs.JSONObject:
1368        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1369        resp = await self._request(
1370            RequestMethod.POST,
1371            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1372            auth=access_token,
1373        )
1374        assert isinstance(resp, dict)
1375        return resp

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
async def edit_clan( self, access_token: str, /, group_id: int, *, name: Optional[str] = None, about: Optional[str] = None, motto: Optional[str] = None, theme: Optional[str] = None, tags: Optional[collections.abc.Sequence[str]] = None, is_public: Optional[bool] = None, locale: Optional[str] = None, avatar_image_index: Optional[int] = None, membership_option: Union[NoneType, int, aiobungie.MembershipOption] = None, allow_chat: Optional[bool] = None, chat_security: Optional[Literal[0, 1]] = None, call_sign: Optional[str] = None, homepage: Optional[Literal[0, 1, 2]] = None, enable_invite_messaging_for_admins: Optional[bool] = None, default_publicity: Optional[Literal[0, 1, 2]] = None, is_public_topic_admin: Optional[bool] = None) -> None:
1377    async def edit_clan(
1378        self,
1379        access_token: str,
1380        /,
1381        group_id: int,
1382        *,
1383        name: typedefs.NoneOr[str] = None,
1384        about: typedefs.NoneOr[str] = None,
1385        motto: typedefs.NoneOr[str] = None,
1386        theme: typedefs.NoneOr[str] = None,
1387        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1388        is_public: typedefs.NoneOr[bool] = None,
1389        locale: typedefs.NoneOr[str] = None,
1390        avatar_image_index: typedefs.NoneOr[int] = None,
1391        membership_option: typedefs.NoneOr[
1392            typedefs.IntAnd[enums.MembershipOption]
1393        ] = None,
1394        allow_chat: typedefs.NoneOr[bool] = None,
1395        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1396        call_sign: typedefs.NoneOr[str] = None,
1397        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1398        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1399        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1400        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1401    ) -> None:
1402        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1403        payload = {
1404            "name": name,
1405            "about": about,
1406            "motto": motto,
1407            "theme": theme,
1408            "tags": tags,
1409            "isPublic": is_public,
1410            "avatarImageIndex": avatar_image_index,
1411            "isPublicTopicAdminOnly": is_public_topic_admin,
1412            "allowChat": allow_chat,
1413            "chatSecurity": chat_security,
1414            "callsign": call_sign,
1415            "homepage": homepage,
1416            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1417            "defaultPublicity": default_publicity,
1418            "locale": locale,
1419        }
1420        if membership_option is not None:
1421            payload["membershipOption"] = int(membership_option)
1422
1423        await self._request(
1424            RequestMethod.POST,
1425            f"GroupV2/{group_id}/Edit",
1426            json=payload,
1427            auth=access_token,
1428        )

Edit a clan.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id to edit.
Other Parameters
async def edit_clan_options( self, access_token: str, /, group_id: int, *, invite_permissions_override: Optional[bool] = None, update_culture_permissionOverride: Optional[bool] = None, host_guided_game_permission_override: Optional[Literal[0, 1, 2]] = None, update_banner_permission_override: Optional[bool] = None, join_level: Union[NoneType, int, aiobungie.ClanMemberType] = None) -> None:
1430    async def edit_clan_options(
1431        self,
1432        access_token: str,
1433        /,
1434        group_id: int,
1435        *,
1436        invite_permissions_override: typedefs.NoneOr[bool] = None,
1437        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1438        host_guided_game_permission_override: typedefs.NoneOr[
1439            typing.Literal[0, 1, 2]
1440        ] = None,
1441        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1442        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1443    ) -> None:
1444
1445        payload = {
1446            "InvitePermissionOverride": invite_permissions_override,
1447            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1448            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1449            "UpdateBannerPermissionOverride": update_banner_permission_override,
1450            "JoinLevel": int(join_level) if join_level else None,
1451        }
1452
1453        await self._request(
1454            RequestMethod.POST,
1455            f"GroupV2/{group_id}/EditFounderOptions",
1456            json=payload,
1457            auth=access_token,
1458        )

Edit the clan options.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
Other Parameters
  • invite_permissions_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • update_culture_permissionOverride (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • host_guided_game_permission_override (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides: 0 -> None, 1 -> Beginner 2 -> Member. Default is Member for clans, None for groups, although this means nothing for groups.
  • update_banner_permission_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • join_level (aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default is aiobungie.ClanMemberType.BEGINNER
async def fetch_friends(self, access_token: str, /) -> dict[str, typing.Any]:
1460    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1461        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1462        resp = await self._request(
1463            RequestMethod.GET,
1464            "Social/Friends/",
1465            auth=access_token,
1466        )
1467        assert isinstance(resp, dict)
1468        return resp

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> dict[str, typing.Any]:
1470    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1471        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1472        resp = await self._request(
1473            RequestMethod.GET,
1474            "Social/Friends/Requests",
1475            auth=access_token,
1476        )
1477        assert isinstance(resp, dict)
1478        return resp

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1480    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1481        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1482        await self._request(
1483            RequestMethod.POST,
1484            f"Social/Friends/Requests/Accept/{member_id}",
1485            auth=access_token,
1486        )

Accepts a friend relationship with the target user. The user must be on your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to accept.
async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1488    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1489        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1490        await self._request(
1491            RequestMethod.POST,
1492            f"Social/Friends/Add/{member_id}",
1493            auth=access_token,
1494        )

Requests a friend relationship with the target user.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to send the request to.
async def decline_friend_request(self, access_token: str, /, member_id: int) -> None:
1496    async def decline_friend_request(
1497        self, access_token: str, /, member_id: int
1498    ) -> None:
1499        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1500        await self._request(
1501            RequestMethod.POST,
1502            f"Social/Friends/Requests/Decline/{member_id}",
1503            auth=access_token,
1504        )

Decline a friend request with the target user. The user must be in your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to decline.
async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1506    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1507        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1508        await self._request(
1509            RequestMethod.POST,
1510            f"Social/Friends/Remove/{member_id}",
1511            auth=access_token,
1512        )

Removes a friend from your friend list. The user must be in your friend list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove.
async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1514    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1515        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1516        await self._request(
1517            RequestMethod.POST,
1518            f"Social/Friends/Requests/Remove/{member_id}",
1519            auth=access_token,
1520        )

Removes a friend from your friend list requests. The user must be in your outgoing request list.

.. note : This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove from the requested friend list.
async def approve_all_pending_group_users( self, access_token: str, /, group_id: int, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1522    async def approve_all_pending_group_users(
1523        self,
1524        access_token: str,
1525        /,
1526        group_id: int,
1527        message: undefined.UndefinedOr[str] = undefined.Undefined,
1528    ) -> None:
1529        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1530        await self._request(
1531            RequestMethod.POST,
1532            f"GroupV2/{group_id}/Members/ApproveAll",
1533            auth=access_token,
1534            json={"message": str(message)},
1535        )

Apporve all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
  • message (aiobungie.UndefinedOr[str]): An optional message to send with the request. Default is UNDEFINED.
async def deny_all_pending_group_users( self, access_token: str, /, group_id: int, *, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1537    async def deny_all_pending_group_users(
1538        self,
1539        access_token: str,
1540        /,
1541        group_id: int,
1542        *,
1543        message: undefined.UndefinedOr[str] = undefined.Undefined,
1544    ) -> None:
1545        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1546        await self._request(
1547            RequestMethod.POST,
1548            f"GroupV2/{group_id}/Members/DenyAll",
1549            auth=access_token,
1550            json={"message": str(message)},
1551        )

Deny all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
  • message (aiobungie.UndefinedOr[str]): An optional message to send with the request. Default is UNDEFINED.
async def add_optional_conversation( self, access_token: str, /, group_id: int, *, name: Union[aiobungie.UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0) -> None:
1553    async def add_optional_conversation(
1554        self,
1555        access_token: str,
1556        /,
1557        group_id: int,
1558        *,
1559        name: undefined.UndefinedOr[str] = undefined.Undefined,
1560        security: typing.Literal[0, 1] = 0,
1561    ) -> None:
1562        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1563        payload = {"chatName": str(name), "chatSecurity": security}
1564        await self._request(
1565            RequestMethod.POST,
1566            f"GroupV2/{group_id}/OptionalConversations/Add",
1567            json=payload,
1568            auth=access_token,
1569        )

Add a new chat channel to a group.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other parameters

name: aiobungie.UndefinedOr[str] The chat name. Default to UNDEFINED security: typing.Literal[0, 1] The security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
async def edit_optional_conversation( self, access_token: str, /, group_id: int, conversation_id: int, *, name: Union[aiobungie.UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0, enable_chat: bool = False) -> None:
1571    async def edit_optional_conversation(
1572        self,
1573        access_token: str,
1574        /,
1575        group_id: int,
1576        conversation_id: int,
1577        *,
1578        name: undefined.UndefinedOr[str] = undefined.Undefined,
1579        security: typing.Literal[0, 1] = 0,
1580        enable_chat: bool = False,
1581    ) -> None:
1582        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1583        payload = {
1584            "chatEnabled": enable_chat,
1585            "chatName": str(name),
1586            "chatSecurity": security,
1587        }
1588        await self._request(
1589            RequestMethod.POST,
1590            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1591            json=payload,
1592            auth=access_token,
1593        )

Edit the settings of this chat channel.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
  • conversation_id (int): The conversation/chat id.
Other parameters

name: aiobungie.UndefinedOr[str] The new chat name. Default to UNDEFINED security: typing.Literal[0, 1] The new security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`

enable_chat : bool Whether to enable chatting or not. If set to True then chatting will be enabled. Otherwise it will be disabled.

async def transfer_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, aiobungie.MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1595    async def transfer_item(
1596        self,
1597        access_token: str,
1598        /,
1599        item_id: int,
1600        item_hash: int,
1601        character_id: int,
1602        member_type: typedefs.IntAnd[enums.MembershipType],
1603        *,
1604        stack_size: int = 1,
1605        vault: bool = False,
1606    ) -> None:
1607        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1608        payload = {
1609            "characterId": character_id,
1610            "membershipType": int(member_type),
1611            "itemId": item_id,
1612            "itemReferenceHash": item_hash,
1613            "stackSize": stack_size,
1614            "transferToVault": vault,
1615        }
1616        await self._request(
1617            RequestMethod.POST,
1618            "Destiny2/Actions/Items/TransferItem",
1619            json=payload,
1620            auth=access_token,
1621        )

Transfer an item from / to your vault.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id you to transfer.
  • item_hash (int): The item hash.
  • character_id (int): The character id to transfer the item from/to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to trasnfer this item to your valut or not. Defaults to False.
async def pull_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, aiobungie.MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1623    async def pull_item(
1624        self,
1625        access_token: str,
1626        /,
1627        item_id: int,
1628        item_hash: int,
1629        character_id: int,
1630        member_type: typedefs.IntAnd[enums.MembershipType],
1631        *,
1632        stack_size: int = 1,
1633        vault: bool = False,
1634    ) -> None:
1635        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1636        payload = {
1637            "characterId": character_id,
1638            "membershipType": int(member_type),
1639            "itemId": item_id,
1640            "itemReferenceHash": item_hash,
1641            "stackSize": stack_size,
1642            "transferToVault": vault,
1643        }
1644        await self._request(
1645            RequestMethod.POST,
1646            "Destiny2/Actions/Items/PullFromPostmaster",
1647            json=payload,
1648            auth=access_token,
1649        )

pull an item from the postmaster.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id to pull.
  • item_hash (int): The item hash.
  • character_id (int): The character id to pull the item to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to pill this item to your valut or not. Defaults to False.
async def fetch_fireteams( self, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[aiobungie.FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: Union[int, aiobungie.FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, slots_filter: int = 0) -> dict[str, typing.Any]:
1651    async def fetch_fireteams(
1652        self,
1653        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1654        *,
1655        platform: typedefs.IntAnd[
1656            fireteams.FireteamPlatform
1657        ] = fireteams.FireteamPlatform.ANY,
1658        language: typing.Union[
1659            fireteams.FireteamLanguage, str
1660        ] = fireteams.FireteamLanguage.ALL,
1661        date_range: typedefs.IntAnd[
1662            fireteams.FireteamDate
1663        ] = fireteams.FireteamDate.ALL,
1664        page: int = 0,
1665        slots_filter: int = 0,
1666    ) -> typedefs.JSONObject:
1667        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1668        resp = await self._request(
1669            RequestMethod.GET,
1670            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1671        )
1672        assert isinstance(resp, dict)
1673        return resp

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], date_range: Union[int, aiobungie.FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> dict[str, typing.Any]:
1675    async def fetch_avaliable_clan_fireteams(
1676        self,
1677        access_token: str,
1678        group_id: int,
1679        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1680        *,
1681        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1682        language: typing.Union[fireteams.FireteamLanguage, str],
1683        date_range: typedefs.IntAnd[
1684            fireteams.FireteamDate
1685        ] = fireteams.FireteamDate.ALL,
1686        page: int = 0,
1687        public_only: bool = False,
1688        slots_filter: int = 0,
1689    ) -> typedefs.JSONObject:
1690        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1691        resp = await self._request(
1692            RequestMethod.GET,
1693            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1694            json={"langFilter": str(language)},
1695            auth=access_token,
1696        )
1697        assert isinstance(resp, dict)
1698        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> dict[str, typing.Any]:
1700    async def fetch_clan_fireteam(
1701        self, access_token: str, fireteam_id: int, group_id: int
1702    ) -> typedefs.JSONObject:
1703        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1704        resp = await self._request(
1705            RequestMethod.GET,
1706            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1707            auth=access_token,
1708        )
1709        assert isinstance(resp, dict)
1710        return resp

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], filtered: bool = True, page: int = 0) -> dict[str, typing.Any]:
1712    async def fetch_my_clan_fireteams(
1713        self,
1714        access_token: str,
1715        group_id: int,
1716        *,
1717        include_closed: bool = True,
1718        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1719        language: typing.Union[fireteams.FireteamLanguage, str],
1720        filtered: bool = True,
1721        page: int = 0,
1722    ) -> typedefs.JSONObject:
1723        payload = {"groupFilter": filtered, "langFilter": str(language)}
1724        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1725        resp = await self._request(
1726            RequestMethod.GET,
1727            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1728            json=payload,
1729            auth=access_token,
1730        )
1731        assert isinstance(resp, dict)
1732        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_private_clan_fireteams(self, access_token: str, group_id: int, /) -> int:
1734    async def fetch_private_clan_fireteams(
1735        self, access_token: str, group_id: int, /
1736    ) -> int:
1737        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1738        resp = await self._request(
1739            RequestMethod.GET,
1740            f"Fireteam/Clan/{group_id}/ActiveCount",
1741            auth=access_token,
1742        )
1743        assert isinstance(resp, int)
1744        return resp

Fetch the active count of the clan fireteams that are only private.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id.
Returns
  • int: The active fireteams count. Max value returned is 25.
async def fetch_post_activity(self, instance_id: int, /) -> dict[str, typing.Any]:
1746    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1747        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1748        resp = await self._request(
1749            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1750        )
1751        assert isinstance(resp, dict)
1752        return resp

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> dict[str, typing.Any]:
1754    async def search_entities(
1755        self, name: str, entity_type: str, *, page: int = 0
1756    ) -> typedefs.JSONObject:
1757        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1758        resp = await self._request(
1759            RequestMethod.GET,
1760            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1761            json={"page": page},
1762        )
1763        assert isinstance(resp, dict)
1764        return resp

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1766    async def fetch_unique_weapon_history(
1767        self,
1768        membership_id: int,
1769        character_id: int,
1770        membership_type: typedefs.IntAnd[enums.MembershipType],
1771    ) -> typedefs.JSONObject:
1772        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1773        resp = await self._request(
1774            RequestMethod.GET,
1775            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1776        )
1777        assert isinstance(resp, dict)
1778        return resp

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_item( self, member_id: int, item_id: int, membership_type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType]) -> dict[str, typing.Any]:
1780    async def fetch_item(
1781        self,
1782        member_id: int,
1783        item_id: int,
1784        membership_type: typedefs.IntAnd[enums.MembershipType],
1785        components: list[enums.ComponentType],
1786    ) -> typedefs.JSONObject:
1787        collector = _collect_components(components)
1788        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1789        resp = await self._request(
1790            RequestMethod.GET,
1791            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1792        )
1793        assert isinstance(resp, dict)
1794        return resp

Fetch an instanced Destiny 2 item's details.

Parameters
Returns
async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> dict[str, typing.Any]:
1796    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1797        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1798        resp = await self._request(
1799            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1800        )
1801        assert isinstance(resp, dict)
1802        return resp

Fetch the weekly reward state for a clan.

Parameters
  • clan_id (int): The clan id.
Returns
async def fetch_available_locales(self) -> dict[str, typing.Any]:
1804    async def fetch_available_locales(self) -> typedefs.JSONObject:
1805        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1806        resp = await self._request(
1807            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1808        )
1809        assert isinstance(resp, dict)
1810        return resp

Fetch available locales at Bungie.

Returns
async def fetch_common_settings(self) -> dict[str, typing.Any]:
1812    async def fetch_common_settings(self) -> typedefs.JSONObject:
1813        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1814        resp = await self._request(RequestMethod.GET, "Settings")
1815        assert isinstance(resp, dict)
1816        return resp

Fetch the common settings used by Bungie's envirotment.

Returns
async def fetch_user_systems_overrides(self) -> dict[str, typing.Any]:
1818    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1819        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1820        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1821        assert isinstance(resp, dict)
1822        return resp

Fetch a user's specific system overrides.

Returns
async def fetch_global_alerts(self, *, include_streaming: bool = False) -> list[typing.Any]:
1824    async def fetch_global_alerts(
1825        self, *, include_streaming: bool = False
1826    ) -> typedefs.JSONArray:
1827        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1828        resp = await self._request(
1829            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1830        )
1831        assert isinstance(resp, list)
1832        return resp

Fetch any active global alerts.

Parameters
  • include_streaming (bool): If True, the returned results will include streaming alerts. Default is False.
Returns
async def awainitialize_request( self, access_token: str, type: Literal[0, 1], membership_type: Union[int, aiobungie.MembershipType], /, *, affected_item_id: Optional[int] = None, character_id: Optional[int] = None) -> dict[str, typing.Any]:
1834    async def awainitialize_request(
1835        self,
1836        access_token: str,
1837        type: typing.Literal[0, 1],
1838        membership_type: typedefs.IntAnd[enums.MembershipType],
1839        /,
1840        *,
1841        affected_item_id: typing.Optional[int] = None,
1842        character_id: typing.Optional[int] = None,
1843    ) -> typedefs.JSONObject:
1844        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1845
1846        body = {"type": type, "membershipType": int(membership_type)}
1847
1848        if affected_item_id is not None:
1849            body["affectedItemId"] = affected_item_id
1850
1851        if character_id is not None:
1852            body["characterId"] = character_id
1853
1854        resp = await self._request(
1855            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1856        )
1857        assert isinstance(resp, dict)
1858        return resp

Initialize a request to perform an advanced write action.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • type (typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means it None. Otherwise if 1 that means its insert plugs.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
  • affected_item_id (typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values.
  • character_id (typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
async def awaget_action_token(self, access_token: str, correlation_id: str, /) -> dict[str, typing.Any]:
1860    async def awaget_action_token(
1861        self, access_token: str, correlation_id: str, /
1862    ) -> typedefs.JSONObject:
1863        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1864        resp = await self._request(
1865            RequestMethod.POST,
1866            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1867            auth=access_token,
1868        )
1869        assert isinstance(resp, dict)
1870        return resp

Returns the action token if user approves the request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • correlation_id (str): The identifier for the advanced write action request.
Returns
async def awa_provide_authorization_result( self, access_token: str, selection: int, correlation_id: str, nonce: collections.abc.MutableSequence[typing.Union[str, bytes]]) -> int:
1872    async def awa_provide_authorization_result(
1873        self,
1874        access_token: str,
1875        selection: int,
1876        correlation_id: str,
1877        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1878    ) -> int:
1879        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1880
1881        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1882
1883        resp = await self._request(
1884            RequestMethod.POST,
1885            "Destiny2/Awa/AwaProvideAuthorizationResult",
1886            json=body,
1887            auth=access_token,
1888        )
1889        assert isinstance(resp, int)
1890        return resp

Provide the result of the user interaction. Called by the Bungie Destiny App to approve or reject a request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • selection (int): Indication of the selection the user has made (Approving or rejecting the action)
  • correlation_id (str): Correlation ID of the request.
  • nonce (collections.MutableSequence[str, bytes]): Secret nonce received via the PUSH notification.
Returns
  • int: ...
async def fetch_vendors( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], /, components: list[aiobungie.ComponentType], filter: Optional[int] = None) -> dict[str, typing.Any]:
1892    async def fetch_vendors(
1893        self,
1894        access_token: str,
1895        character_id: int,
1896        membership_id: int,
1897        membership_type: typedefs.IntAnd[enums.MembershipType],
1898        /,
1899        components: list[enums.ComponentType],
1900        filter: typing.Optional[int] = None,
1901    ) -> typedefs.JSONObject:
1902        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1903        components_ = _collect_components(components)
1904        route = (
1905            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1906            f"/Character/{character_id}/Vendors/?components={components_}"
1907        )
1908
1909        if filter is not None:
1910            route = route + f"&filter={filter}"
1911
1912        resp = await self._request(
1913            RequestMethod.GET,
1914            route,
1915            auth=access_token,
1916        )
1917        assert isinstance(resp, dict)
1918        return resp

Get currently available vendors from the list of vendors that can possibly have rotating inventory.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
  • filter (int): Filters the type of items returned from the vendor. This can be left to None.
Returns
async def fetch_vendor( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], vendor_hash: int, /, components: list[aiobungie.ComponentType]) -> dict[str, typing.Any]:
1920    async def fetch_vendor(
1921        self,
1922        access_token: str,
1923        character_id: int,
1924        membership_id: int,
1925        membership_type: typedefs.IntAnd[enums.MembershipType],
1926        vendor_hash: int,
1927        /,
1928        components: list[enums.ComponentType],
1929    ) -> typedefs.JSONObject:
1930        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1931        components_ = _collect_components(components)
1932        resp = await self._request(
1933            RequestMethod.GET,
1934            (
1935                f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}"
1936                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1937            ),
1938            auth=access_token,
1939        )
1940        assert isinstance(resp, dict)
1941        return resp

Fetch details for a specific vendor.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • vendor_hash (int): The vendor hash to return the details for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
async def fetch_application_api_usage( self, access_token: str, application_id: int, /, *, start: Optional[datetime.datetime] = None, end: Optional[datetime.datetime] = None) -> dict[str, typing.Any]:
1943    async def fetch_application_api_usage(
1944        self,
1945        access_token: str,
1946        application_id: int,
1947        /,
1948        *,
1949        start: typing.Optional[datetime.datetime] = None,
1950        end: typing.Optional[datetime.datetime] = None,
1951    ) -> typedefs.JSONObject:
1952
1953        end_date, start_date = time.parse_date_range(end, start)
1954        resp = await self._request(
1955            RequestMethod.GET,
1956            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1957            auth=access_token,
1958        )
1959        assert isinstance(resp, dict)
1960        return resp

Fetch a Bungie application's API usage.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • application_id (int): The application id to get.
Other Parameters
  • start (typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.

    If this is left to None. It will return the last 24 hours.

  • end (typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.

    If this is left to None. It will return now.

Example
import datetime

# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
    start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
async def fetch_bungie_applications(self) -> list[typing.Any]:
1962    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1963        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1964        assert isinstance(resp, list)
1965        return resp

Fetch details for applications created by Bungie.

Returns
async def fetch_content_type(self, type: str, /) -> dict[str, typing.Any]:
1967    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1968        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1969        assert isinstance(resp, dict)
1970        return resp
async def fetch_content_by_id( self, id: int, locale: str, /, *, head: bool = False) -> dict[str, typing.Any]:
1972    async def fetch_content_by_id(
1973        self, id: int, locale: str, /, *, head: bool = False
1974    ) -> typedefs.JSONObject:
1975        resp = await self._request(
1976            RequestMethod.GET,
1977            f"Content/GetContentById/{id}/{locale}/",
1978            json={"head": head},
1979        )
1980        assert isinstance(resp, dict)
1981        return resp
async def fetch_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, head: bool = False) -> dict[str, typing.Any]:
1983    async def fetch_content_by_tag_and_type(
1984        self, locale: str, tag: str, type: str, *, head: bool = False
1985    ) -> typedefs.JSONObject:
1986        resp = await self._request(
1987            RequestMethod.GET,
1988            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1989            json={"head": head},
1990        )
1991        assert isinstance(resp, dict)
1992        return resp
async def search_content_with_text( self, locale: str, /, content_type: str, search_text: str, tag: str, *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, source: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
1994    async def search_content_with_text(
1995        self,
1996        locale: str,
1997        /,
1998        content_type: str,
1999        search_text: str,
2000        tag: str,
2001        *,
2002        page: undefined.UndefinedOr[int] = undefined.Undefined,
2003        source: undefined.UndefinedOr[str] = undefined.Undefined,
2004    ) -> typedefs.JSONObject:
2005
2006        body: typedefs.JSONObject = {}
2007
2008        body["ctype"] = content_type
2009        body["searchtext"] = search_text
2010        body["tag"] = tag
2011
2012        if page is not undefined.Undefined:
2013            body["currentpage"] = page
2014        else:
2015            body["currentpage"] = 1
2016
2017        if source is not undefined.Undefined:
2018            body["source"] = source
2019        else:
2020            source = ""
2021        resp = await self._request(
2022            RequestMethod.GET, f"Content/Search/{locale}/", json=body
2023        )
2024        assert isinstance(resp, dict)
2025        return resp
async def search_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED) -> dict[str, typing.Any]:
2027    async def search_content_by_tag_and_type(
2028        self,
2029        locale: str,
2030        tag: str,
2031        type: str,
2032        *,
2033        page: undefined.UndefinedOr[int] = undefined.Undefined,
2034    ) -> typedefs.JSONObject:
2035        body: typedefs.JSONObject = {}
2036        body["currentpage"] = 1 if page is undefined.Undefined else page
2037        resp = await self._request(
2038            RequestMethod.GET,
2039            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
2040            json=body,
2041        )
2042        assert isinstance(resp, dict)
2043        return resp
async def search_help_articles(self, text: str, size: str, /) -> dict[str, typing.Any]:
2045    async def search_help_articles(
2046        self, text: str, size: str, /
2047    ) -> typedefs.JSONObject:
2048        resp = await self._request(
2049            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
2050        )
2051        assert isinstance(resp, dict)
2052        return resp
async def fetch_topics_page( self, category_filter: int, group: int, date_filter: int, sort: Union[str, bytes], *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, locales: Union[aiobungie.UndefinedType, collections.abc.Iterable[str]] = UNDEFINED, tag_filter: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
2054    async def fetch_topics_page(
2055        self,
2056        category_filter: int,
2057        group: int,
2058        date_filter: int,
2059        sort: typing.Union[str, bytes],
2060        *,
2061        page: undefined.UndefinedOr[int] = undefined.Undefined,
2062        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2063        tag_filter: undefined.UndefinedOr[str] = undefined.Undefined,
2064    ) -> typedefs.JSONObject:
2065
2066        body: typedefs.JSONObject = {}
2067        if locales is not undefined.Undefined:
2068            body["locales"] = ",".join(str(locales))
2069        else:
2070            body["locales"] = ",".join([])
2071
2072        if tag_filter is not undefined.Undefined:
2073            body["tagstring"] = tag_filter
2074        else:
2075            body["tagstring"] = ""
2076
2077        page = 0 if page is not undefined.Undefined else page
2078
2079        resp = await self._request(
2080            RequestMethod.GET,
2081            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
2082            json=body,
2083        )
2084        assert isinstance(resp, dict)
2085        return resp
async def fetch_core_topics_page( self, category_filter: int, date_filter: int, sort: Union[str, bytes], *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, locales: Union[aiobungie.UndefinedType, collections.abc.Iterable[str]] = UNDEFINED) -> dict[str, typing.Any]:
2087    async def fetch_core_topics_page(
2088        self,
2089        category_filter: int,
2090        date_filter: int,
2091        sort: typing.Union[str, bytes],
2092        *,
2093        page: undefined.UndefinedOr[int] = undefined.Undefined,
2094        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2095    ) -> typedefs.JSONObject:
2096        body: typedefs.JSONObject = {}
2097
2098        if locales is not undefined.Undefined:
2099            body["locales"] = ",".join(str(locales))
2100        else:
2101            body["locales"] = ",".join([])
2102
2103        resp = await self._request(
2104            RequestMethod.GET,
2105            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}"
2106            f"/{sort!s}/{date_filter}/{category_filter}/",
2107            json=body,
2108        )
2109        assert isinstance(resp, dict)
2110        return resp
async def fetch_posts_threaded_page( self, parent_post: bool, page: int, page_size: int, parent_post_id: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2112    async def fetch_posts_threaded_page(
2113        self,
2114        parent_post: bool,
2115        page: int,
2116        page_size: int,
2117        parent_post_id: int,
2118        reply_size: int,
2119        root_thread_mode: bool,
2120        sort_mode: int,
2121        show_banned: typing.Optional[str] = None,
2122    ) -> typedefs.JSONObject:
2123        resp = await self._request(
2124            RequestMethod.GET,
2125            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2126            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2127            json={"showbanned": show_banned},
2128        )
2129        assert isinstance(resp, dict)
2130        return resp
async def fetch_posts_threaded_page_from_child( self, child_id: bool, page: int, page_size: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2132    async def fetch_posts_threaded_page_from_child(
2133        self,
2134        child_id: bool,
2135        page: int,
2136        page_size: int,
2137        reply_size: int,
2138        root_thread_mode: bool,
2139        sort_mode: int,
2140        show_banned: typing.Optional[str] = None,
2141    ) -> typedefs.JSONObject:
2142        resp = await self._request(
2143            RequestMethod.GET,
2144            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2145            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2146            json={"showbanned": show_banned},
2147        )
2148        assert isinstance(resp, dict)
2149        return resp
async def fetch_post_and_parent( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2151    async def fetch_post_and_parent(
2152        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2153    ) -> typedefs.JSONObject:
2154        resp = await self._request(
2155            RequestMethod.GET,
2156            f"Forum/GetPostAndParent/{child_id}/",
2157            json={"showbanned": show_banned},
2158        )
2159        assert isinstance(resp, dict)
2160        return resp
async def fetch_posts_and_parent_awaiting( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2162    async def fetch_posts_and_parent_awaiting(
2163        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2164    ) -> typedefs.JSONObject:
2165        resp = await self._request(
2166            RequestMethod.GET,
2167            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2168            json={"showbanned": show_banned},
2169        )
2170        assert isinstance(resp, dict)
2171        return resp
async def fetch_topic_for_content(self, content_id: int, /) -> int:
2173    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2174        resp = await self._request(
2175            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2176        )
2177        assert isinstance(resp, int)
2178        return resp
async def fetch_forum_tag_suggestions(self, partial_tag: str, /) -> dict[str, typing.Any]:
2180    async def fetch_forum_tag_suggestions(
2181        self, partial_tag: str, /
2182    ) -> typedefs.JSONObject:
2183        resp = await self._request(
2184            RequestMethod.GET,
2185            "Forum/GetForumTagSuggestions/",
2186            json={"partialtag": partial_tag},
2187        )
2188        assert isinstance(resp, dict)
2189        return resp
async def fetch_poll(self, topic_id: int, /) -> dict[str, typing.Any]:
2191    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2192        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2193        assert isinstance(resp, dict)
2194        return resp
async def fetch_recuirement_thread_summaries(self) -> list[typing.Any]:
2196    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2197        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2198        assert isinstance(resp, list)
2199        return resp
async def fetch_available_avatars(self) -> collections.abc.Mapping[str, int]:
2217    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2218        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2219        assert isinstance(resp, dict)
2220        return resp
async def fetch_user_clan_invite_setting( self, access_token: str, /, membership_type: Union[int, aiobungie.MembershipType]) -> bool:
2222    async def fetch_user_clan_invite_setting(
2223        self,
2224        access_token: str,
2225        /,
2226        membership_type: typedefs.IntAnd[enums.MembershipType],
2227    ) -> bool:
2228        resp = await self._request(
2229            RequestMethod.GET,
2230            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2231            auth=access_token,
2232        )
2233        assert isinstance(resp, bool)
2234        return resp
async def fetch_banned_group_members( self, access_token: str, group_id: int, /, *, page: int = 1) -> dict[str, typing.Any]:
2236    async def fetch_banned_group_members(
2237        self, access_token: str, group_id: int, /, *, page: int = 1
2238    ) -> typedefs.JSONObject:
2239        resp = await self._request(
2240            RequestMethod.GET,
2241            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2242            auth=access_token,
2243        )
2244        assert isinstance(resp, dict)
2245        return resp
async def fetch_pending_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2247    async def fetch_pending_group_memberships(
2248        self, access_token: str, group_id: int, /, *, current_page: int = 1
2249    ) -> typedefs.JSONObject:
2250        resp = await self._request(
2251            RequestMethod.GET,
2252            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2253            auth=access_token,
2254        )
2255        assert isinstance(resp, dict)
2256        return resp
async def fetch_invited_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2258    async def fetch_invited_group_memberships(
2259        self, access_token: str, group_id: int, /, *, current_page: int = 1
2260    ) -> typedefs.JSONObject:
2261        resp = await self._request(
2262            RequestMethod.GET,
2263            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2264            auth=access_token,
2265        )
2266        assert isinstance(resp, dict)
2267        return resp
async def invite_member_to_group( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], *, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
2269    async def invite_member_to_group(
2270        self,
2271        access_token: str,
2272        /,
2273        group_id: int,
2274        membership_id: int,
2275        membership_type: typedefs.IntAnd[enums.MembershipType],
2276        *,
2277        message: undefined.UndefinedOr[str] = undefined.Undefined,
2278    ) -> typedefs.JSONObject:
2279        resp = await self._request(
2280            RequestMethod.POST,
2281            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2282            auth=access_token,
2283            json={"message": str(message)},
2284        )
2285        assert isinstance(resp, dict)
2286        return resp
async def cancel_group_member_invite( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
2288    async def cancel_group_member_invite(
2289        self,
2290        access_token: str,
2291        /,
2292        group_id: int,
2293        membership_id: int,
2294        membership_type: typedefs.IntAnd[enums.MembershipType],
2295    ) -> typedefs.JSONObject:
2296        resp = await self._request(
2297            RequestMethod.POST,
2298            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2299            auth=access_token,
2300        )
2301        assert isinstance(resp, dict)
2302        return resp
async def fetch_historical_definition(self) -> dict[str, typing.Any]:
2304    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2305        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2306        assert isinstance(resp, dict)
2307        return resp
async def fetch_historical_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], day_start: datetime.datetime, day_end: datetime.datetime, groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]], modes: collections.abc.Sequence[typing.Union[int, aiobungie.GameMode]], *, period_type: aiobungie.internal.enums.PeriodType = <PeriodType.ALL_TIME: 2>) -> dict[str, typing.Any]:
2309    async def fetch_historical_stats(
2310        self,
2311        character_id: int,
2312        membership_id: int,
2313        membership_type: typedefs.IntAnd[enums.MembershipType],
2314        day_start: datetime.datetime,
2315        day_end: datetime.datetime,
2316        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2317        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2318        *,
2319        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2320    ) -> typedefs.JSONObject:
2321
2322        end, start = time.parse_date_range(day_end, day_start)
2323        resp = await self._request(
2324            RequestMethod.GET,
2325            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2326            json={
2327                "dayend": end,
2328                "daystart": start,
2329                "groups": [str(int(group)) for group in groups],
2330                "modes": [str(int(mode)) for mode in modes],
2331                "periodType": int(period_type),
2332            },
2333        )
2334        assert isinstance(resp, dict)
2335        return resp

Fetch historical stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • day_start (datetime.datetime): The start of the day to return the stats for.
  • day_end (datetime.datetime): The end of the day to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
  • modes (list[aiobungie.GameMode | int]): A list of game modes to return.
  • period_type (aiobungie.enums.PeriodType): The period type to return the stats for. This will return ALL_TIME by default if not modified.
Returns
async def fetch_historical_stats_for_account( self, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]]) -> dict[str, typing.Any]:
2337    async def fetch_historical_stats_for_account(
2338        self,
2339        membership_id: int,
2340        membership_type: typedefs.IntAnd[enums.MembershipType],
2341        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2342    ) -> typedefs.JSONObject:
2343        resp = await self._request(
2344            RequestMethod.GET,
2345            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2346            json={"groups": [str(int(group)) for group in groups]},
2347        )
2348        assert isinstance(resp, dict)
2349        return resp

Fetch historical stats for an account's membership.

Parameters
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], /) -> dict[str, typing.Any]:
2351    async def fetch_aggregated_activity_stats(
2352        self,
2353        character_id: int,
2354        membership_id: int,
2355        membership_type: typedefs.IntAnd[enums.MembershipType],
2356        /,
2357    ) -> typedefs.JSONObject:
2358        resp = await self._request(
2359            RequestMethod.GET,
2360            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2361            f"Character/{character_id}/Stats/AggregateActivityStats/",
2362        )
2363        assert isinstance(resp, dict)
2364        return resp

Fetch aggregated activity stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
class RESTPool:
244class RESTPool:
245    """Pool of `RESTClient` instances.
246
247    This allows to create multiple instances of `RESTClient`s that can be acquired
248    which share the same config and metadata.
249
250    Example
251    -------
252    ```py
253    import aiobungie
254    import asyncio
255
256    client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
257
258    # Using a context manager to acquire an instance
259    # of the pool and close the connection after finishing.
260
261    async def first() -> str:
262        async with client_pool.acquire() as client:
263            return client.build_oauth2_url()
264
265    async def second() -> None:
266        async with client_pool.acquire() as client:
267            new_tokens = await client.refresh_access_token("token")
268            client.metadata['tokens'] = new_tokens
269
270    # Client instances are independent from first and second.
271    await asyncio.gather(first(), second())
272    ```
273
274    Parameters
275    ----------
276    token : `str`
277        A valid application token from Bungie's developer portal.
278
279    Other Parameters
280    ----------------
281    max_retries : `int`
282        The max retries number to retry if the request hit a `5xx` status code.
283    max_ratelimit_retries : `int`
284        The max retries number to retry if the request hit a `429` status code. Defaults to `3`.
285    client_secret : `typing.Optional[str]`
286        An optional application client secret,
287        This is only needed if you're fetching OAuth2 tokens with this client.
288    client_id : `typing.Optional[int]`
289        An optional application client id,
290        This is only needed if you're fetching OAuth2 tokens with this client.
291    enable_debugging : `bool | str`
292        Whether to enable logging responses or not.
293
294    Logging Levels
295    --------------
296    * `False`: This will disable logging.
297    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
298    Like the response status, route, taken time and so on.
299    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
300    """
301
302    __slots__ = (
303        "_token",
304        "_max_retries",
305        "_client_secret",
306        "_client_id",
307        "_max_rate_limit_retries",
308        "_metadata",
309        "_enable_debug",
310    )
311
312    # Looks like mypy doesn't like this.
313    if typing.TYPE_CHECKING:
314        _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int]
315
316    def __init__(
317        self,
318        token: str,
319        /,
320        client_secret: typing.Optional[str] = None,
321        client_id: typing.Optional[int] = None,
322        *,
323        max_retries: int = 4,
324        max_rate_limit_retries: int = 3,
325        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
326    ) -> None:
327        self._client_secret = client_secret
328        self._client_id = client_id
329        self._token: str = token
330        self._max_retries = max_retries
331        self._max_rate_limit_retries = max_rate_limit_retries
332        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
333        self._enable_debug = enable_debugging
334
335    @property
336    def client_id(self) -> typing.Optional[int]:
337        return self._client_id
338
339    @property
340    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
341        """Pool's Metadata. This is different from client instance metadata."""
342        return self._metadata
343
344    @typing.final
345    def acquire(self) -> RESTClient:
346        """Acquires a new `RESTClient` instance from this REST pool.
347
348        Returns
349        -------
350        `RESTClient`
351            An instance of a REST client.
352        """
353        instance = RESTClient(
354            self._token,
355            client_secret=self._client_secret,
356            client_id=self._client_id,
357            max_retries=self._max_retries,
358            max_ratelimit_retries=self._max_rate_limit_retries,
359            enable_debugging=self._enable_debug,
360        )
361        return instance

Pool of RESTClient instances.

This allows to create multiple instances of RESTClients that can be acquired which share the same config and metadata.

Example
import aiobungie
import asyncio

client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')

# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.

async def first() -> str:
    async with client_pool.acquire() as client:
        return client.build_oauth2_url()

async def second() -> None:
    async with client_pool.acquire() as client:
        new_tokens = await client.refresh_access_token("token")
        client.metadata['tokens'] = new_tokens

# Client instances are independent from first and second.
await asyncio.gather(first(), second())
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • max_ratelimit_retries (int): The max retries number to retry if the request hit a 429 status code. Defaults to 3.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information. Like the response status, route, taken time and so on.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
RESTPool( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, max_retries: int = 4, max_rate_limit_retries: int = 3, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
316    def __init__(
317        self,
318        token: str,
319        /,
320        client_secret: typing.Optional[str] = None,
321        client_id: typing.Optional[int] = None,
322        *,
323        max_retries: int = 4,
324        max_rate_limit_retries: int = 3,
325        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
326    ) -> None:
327        self._client_secret = client_secret
328        self._client_id = client_id
329        self._token: str = token
330        self._max_retries = max_retries
331        self._max_rate_limit_retries = max_rate_limit_retries
332        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
333        self._enable_debug = enable_debugging
client_id: Optional[int]
metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

Pool's Metadata. This is different from client instance metadata.

@typing.final
def acquire(self) -> aiobungie.RESTClient:
344    @typing.final
345    def acquire(self) -> RESTClient:
346        """Acquires a new `RESTClient` instance from this REST pool.
347
348        Returns
349        -------
350        `RESTClient`
351            An instance of a REST client.
352        """
353        instance = RESTClient(
354            self._token,
355            client_secret=self._client_secret,
356            client_id=self._client_id,
357            max_retries=self._max_retries,
358            max_ratelimit_retries=self._max_rate_limit_retries,
359            enable_debugging=self._enable_debug,
360        )
361        return instance

Acquires a new RESTClient instance from this REST pool.

Returns
@typing.final
class Race(builtins.int, aiobungie.Enum):
496@typing.final
497class Race(int, Enum):
498    """An Enum for Destiny races."""
499
500    HUMAN = 0
501    AWOKEN = 1
502    EXO = 2
503    UNKNOWN = 3

An Enum for Destiny races.

HUMAN = <Race.HUMAN: 0>
AWOKEN = <Race.AWOKEN: 1>
EXO = <Race.EXO: 2>
UNKNOWN = <Race.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Raid(builtins.int, aiobungie.Enum):
148@typing.final
149class Raid(int, Enum):
150    """An Enum for all available raids in Destiny 2."""
151
152    DSC = 910380154
153    """Deep Stone Crypt"""
154
155    LW = 2122313384
156    """Last Wish"""
157
158    VOG = 3881495763
159    """Normal Valut of Glass"""
160
161    GOS = 3458480158
162    """Garden Of Salvation"""

An Enum for all available raids in Destiny 2.

DSC = <Raid.DSC: 910380154>

Deep Stone Crypt

LW = <Raid.LW: 2122313384>

Last Wish

VOG = <Raid.VOG: 3881495763>

Normal Valut of Glass

GOS = <Raid.GOS: 3458480158>

Garden Of Salvation

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class RateLimitedError(aiobungie.HTTPError):
200@attrs.define(auto_exc=True)
201class RateLimitedError(HTTPError):
202    """Raised when being hit with ratelimits."""
203
204    http_status: http.HTTPStatus = attrs.field(
205        default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False
206    )
207    """The request response http status."""
208
209    url: typedefs.StrOrURL
210    """The URL/endpoint caused this error."""
211
212    body: typing.Any
213    """The response body."""
214
215    retry_after: float = attrs.field(default=0.0)
216    """The amount of seconds you need to wait before retrying to requests."""
217
218    message: str = attrs.field(init=False)
219    """A Bungie human readable message describes the cause of the error."""
220
221    @message.default  # type: ignore
222    def _(self) -> str:
223        return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!"
224
225    def __str__(self) -> str:
226        return self.message

Raised when being hit with ratelimits.

RateLimitedError(url: Union[str, yarl.URL], body: Any, retry_after: float = 0.0)
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default):
3    self.http_status = attr_dict['http_status'].default
4    self.url = url
5    self.body = body
6    self.retry_after = retry_after
7    self.message = __attr_factory_message(self)
8    BaseException.__init__(self, self.url,self.body,self.retry_after)

Method generated by attrs for class RateLimitedError.

http_status: http.HTTPStatus

The request response http status.

url: Union[str, yarl.URL]

The URL/endpoint caused this error.

body: Any

The response body.

retry_after: float

The amount of seconds you need to wait before retrying to requests.

message: str

A Bungie human readable message describes the cause of the error.

Inherited Members
builtins.BaseException
with_traceback
args
@typing.final
class RecordState(aiobungie.Flag):
49@typing.final
50class RecordState(enums.Flag):
51    """An enum for records component states."""
52
53    NONE = 0
54    REDEEMED = 1
55    UNAVAILABLE = 2
56    OBJECTIVE_NOT_COMPLETED = 4
57    OBSCURED = 8
58    INVISIBLE = 16
59    ENTITLEMENT_UNOWNED = 32
60    CAN_EQUIP_TITLE = 64

An enum for records component states.

NONE = <RecordState.NONE: 0>
REDEEMED = <RecordState.REDEEMED: 1>
UNAVAILABLE = <RecordState.UNAVAILABLE: 2>
OBJECTIVE_NOT_COMPLETED = <RecordState.OBJECTIVE_NOT_COMPLETED: 4>
OBSCURED = <RecordState.OBSCURED: 8>
INVISIBLE = <RecordState.INVISIBLE: 16>
ENTITLEMENT_UNOWNED = <RecordState.ENTITLEMENT_UNOWNED: 32>
CAN_EQUIP_TITLE = <RecordState.CAN_EQUIP_TITLE: 64>
Inherited Members
Flag
name
value
@typing.final
class Relationship(builtins.int, aiobungie.Enum):
691@typing.final
692class Relationship(int, Enum):
693    """An enum for bungie friends relationship types."""
694
695    UNKNOWN = 0
696    FRIEND = 1
697    INCOMING_REQUEST = 2
698    OUTGOING_REQUEST = 3

An enum for bungie friends relationship types.

UNKNOWN = <Relationship.UNKNOWN: 0>
FRIEND = <Relationship.FRIEND: 1>
INCOMING_REQUEST = <Relationship.INCOMING_REQUEST: 2>
OUTGOING_REQUEST = <Relationship.OUTGOING_REQUEST: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RequestMethod(builtins.str, aiobungie.Enum):
225class RequestMethod(str, enums.Enum):
226    """HTTP request methods enum."""
227
228    GET = "GET"
229    """GET methods."""
230    POST = "POST"
231    """POST methods."""
232    PUT = "PUT"
233    """PUT methods."""
234    PATCH = "PATCH"
235    """PATCH methods."""
236    DELETE = "DELETE"
237    """DELETE methods"""

HTTP request methods enum.

GET = <RequestMethod.GET: GET>

GET methods.

POST = <RequestMethod.POST: POST>

POST methods.

PUT = <RequestMethod.PUT: PUT>

PUT methods.

PATCH = <RequestMethod.PATCH: PATCH>

PATCH methods.

DELETE = <RequestMethod.DELETE: DELETE>

DELETE methods

Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@attrs.define(auto_exc=True)
class ResponseError(aiobungie.HTTPException):
195@attrs.define(auto_exc=True)
196class ResponseError(HTTPException):
197    """Standard HTTP responses exception."""

Standard HTTP responses exception.

ResponseError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class ResponseError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class Stat(builtins.int, aiobungie.Enum):
518@typing.final
519class Stat(int, Enum):
520    """An Enum for Destiny 2 character stats."""
521
522    NONE = 0
523    MOBILITY = 2996146975
524    RESILIENCE = 392767087
525    RECOVERY = 1943323491
526    DISCIPLINE = 1735777505
527    INTELLECT = 144602215
528    STRENGTH = 4244567218
529    LIGHT_POWER = 1935470627

An Enum for Destiny 2 character stats.

NONE = <Stat.NONE: 0>
MOBILITY = <Stat.MOBILITY: 2996146975>
RESILIENCE = <Stat.RESILIENCE: 392767087>
RECOVERY = <Stat.RECOVERY: 1943323491>
DISCIPLINE = <Stat.DISCIPLINE: 1735777505>
INTELLECT = <Stat.INTELLECT: 144602215>
STRENGTH = <Stat.STRENGTH: 4244567218>
LIGHT_POWER = <Stat.LIGHT_POWER: 1935470627>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
TRACE = 5
@typing.final
class TierType(builtins.int, aiobungie.Enum):
633@typing.final
634class TierType(int, Enum):
635    """An enum for a Destiny 2 item tier type."""
636
637    UNKNOWN = 0
638    CURRENCY = 1
639    BASIC = 2
640    COMMON = 3
641    RARE = 4
642    SUPERIOR = 5
643    EXOTIC = 6

An enum for a Destiny 2 item tier type.

UNKNOWN = <TierType.UNKNOWN: 0>
CURRENCY = <TierType.CURRENCY: 1>
BASIC = <TierType.BASIC: 2>
COMMON = <TierType.COMMON: 3>
RARE = <TierType.RARE: 4>
SUPERIOR = <TierType.SUPERIOR: 5>
EXOTIC = <TierType.EXOTIC: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class TransferStatus(aiobungie.Flag):
743@typing.final
744class TransferStatus(Flag):
745    """An enum for items transfer statuses."""
746
747    CAN_TRANSFER = 0
748    """The item can be transferred."""
749    IS_EQUIPPED = 1
750    """You can't transfer since the item is equipped."""
751    NOT_TRASNFERRABLE = 2
752    """This item can not be transferred."""
753    COULD_BE_TRANSFERRED = 4
754    """You can trasnfer the item. But the place you're trying to put it at has no space for it."""

An enum for items transfer statuses.

CAN_TRANSFER = <TransferStatus.CAN_TRANSFER: 0>

The item can be transferred.

IS_EQUIPPED = <TransferStatus.IS_EQUIPPED: 1>

You can't transfer since the item is equipped.

NOT_TRASNFERRABLE = <TransferStatus.NOT_TRASNFERRABLE: 2>

This item can not be transferred.

COULD_BE_TRANSFERRED = <TransferStatus.COULD_BE_TRANSFERRED: 4>

You can trasnfer the item. But the place you're trying to put it at has no space for it.

Inherited Members
Flag
name
value
@attrs.define(auto_exc=True)
class Unauthorized(aiobungie.HTTPException):
138@attrs.define(auto_exc=True)
139class Unauthorized(HTTPException):
140    """Unauthorized access."""
141
142    http_status: http.HTTPStatus = attrs.field(
143        default=http.HTTPStatus.UNAUTHORIZED, init=False
144    )

Unauthorized access.

Unauthorized( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Unauthorized.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
Undefined = UNDEFINED
UndefinedOr = typing.Union[aiobungie.UndefinedType, +_T]
class UndefinedType:
33class UndefinedType:
34    """An `UNDEFINED` type."""
35
36    __instance: typing.Optional[UndefinedType] = None
37
38    def __bool__(self) -> typing.Literal[False]:
39        return False
40
41    def __int__(self) -> typing.Literal[0]:
42        return 0
43
44    def __repr__(self) -> str:
45        return "UNDEFINED"
46
47    def __str__(self) -> str:
48        return "UNDEFINED"
49
50    def __new__(cls) -> UndefinedType:
51        if cls.__instance is None:
52            o = super().__new__(cls)
53            cls.__instance = o
54        return cls.__instance

An UNDEFINED type.

UndefinedType()
@typing.final
class ValueUIStyle(builtins.int, aiobungie.Enum):
75@typing.final
76class ValueUIStyle(int, enums.Enum):
77    AUTOMATIC = 0
78    FRACTION = 1
79    CHECK_BOX = 2
80    PERCENTAGE = 3
81    DATETIME = 4
82    FRACTION_FLOAT = 5
83    INTEGER = 6
84    TIME_DURATION = 7
85    HIDDEN = 8
86    MULTIPLIER = 9
87    GREEN_PIPS = 10
88    RED_PIPS = 11
89    EXPLICIT_PERCENTAGE = 12
90    RAW_FLOAT = 13
91    LEVEL_AND_REWARD = 14

An enumeration.

AUTOMATIC = <ValueUIStyle.AUTOMATIC: 0>
FRACTION = <ValueUIStyle.FRACTION: 1>
CHECK_BOX = <ValueUIStyle.CHECK_BOX: 2>
PERCENTAGE = <ValueUIStyle.PERCENTAGE: 3>
DATETIME = <ValueUIStyle.DATETIME: 4>
FRACTION_FLOAT = <ValueUIStyle.FRACTION_FLOAT: 5>
INTEGER = <ValueUIStyle.INTEGER: 6>
TIME_DURATION = <ValueUIStyle.TIME_DURATION: 7>
HIDDEN = <ValueUIStyle.HIDDEN: 8>
MULTIPLIER = <ValueUIStyle.MULTIPLIER: 9>
GREEN_PIPS = <ValueUIStyle.GREEN_PIPS: 10>
RED_PIPS = <ValueUIStyle.RED_PIPS: 11>
EXPLICIT_PERCENTAGE = <ValueUIStyle.EXPLICIT_PERCENTAGE: 12>
RAW_FLOAT = <ValueUIStyle.RAW_FLOAT: 13>
LEVEL_AND_REWARD = <ValueUIStyle.LEVEL_AND_REWARD: 14>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Vendor(builtins.int, aiobungie.Enum):
245@typing.final
246class Vendor(int, Enum):
247    """An Enum for all available vendors in Destiny 2."""
248
249    ZAVALA = 69482069
250    XUR = 2190858386
251    BANSHE = 672118013
252    SPIDER = 863940356
253    SHAXX = 3603221665
254    KADI = 529635856
255    """Postmaster exo."""
256    YUNA = 1796504621
257    """Asia servers only."""
258    EVERVERSE = 3361454721
259    AMANDA = 460529231
260    """Amanda holiday"""
261    CROW = 3611983588
262    HAWTHORNE = 3347378076
263    ADA1 = 350061650
264    DRIFTER = 248695599
265    IKORA = 1976548992
266    SAINT = 765357505
267    """Saint-14"""
268    ERIS_MORN = 1616085565
269    SHAW_HAWN = 1816541247
270    """COSMODROME Guy"""
271    VARIKS = 2531198101

An Enum for all available vendors in Destiny 2.

ZAVALA = <Vendor.ZAVALA: 69482069>
XUR = <Vendor.XUR: 2190858386>
BANSHE = <Vendor.BANSHE: 672118013>
SPIDER = <Vendor.SPIDER: 863940356>
SHAXX = <Vendor.SHAXX: 3603221665>
KADI = <Vendor.KADI: 529635856>

Postmaster exo.

YUNA = <Vendor.YUNA: 1796504621>

Asia servers only.

EVERVERSE = <Vendor.EVERVERSE: 3361454721>
AMANDA = <Vendor.AMANDA: 460529231>

Amanda holiday

CROW = <Vendor.CROW: 3611983588>
HAWTHORNE = <Vendor.HAWTHORNE: 3347378076>
ADA1 = <Vendor.ADA1: 350061650>
DRIFTER = <Vendor.DRIFTER: 248695599>
IKORA = <Vendor.IKORA: 1976548992>
SAINT = <Vendor.SAINT: 765357505>

Saint-14

ERIS_MORN = <Vendor.ERIS_MORN: 1616085565>
SHAW_HAWN = <Vendor.SHAW_HAWN: 1816541247>

COSMODROME Guy

VARIKS = <Vendor.VARIKS: 2531198101>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class WeaponType(builtins.int, aiobungie.Enum):
532@typing.final
533class WeaponType(int, Enum):
534    """Enums for The three Destiny Weapon Types"""
535
536    NONE = 0
537    KINETIC = 1498876634
538    ENERGY = 2465295065
539    POWER = 953998645

Enums for The three Destiny Weapon Types

NONE = <WeaponType.NONE: 0>
KINETIC = <WeaponType.KINETIC: 1498876634>
ENERGY = <WeaponType.ENERGY: 2465295065>
POWER = <WeaponType.POWER: 953998645>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
annotations = _Feature((3, 7, 0, 'beta', 1), (3, 11, 0, 'alpha', 0), 16777216)
def into_iter( iterable: collections.abc.Iterable[~Item]) -> aiobungie.FlatIterator[~Item]:
588def into_iter(
589    iterable: collections.Iterable[Item],
590) -> FlatIterator[Item]:
591    """Transform an iterable into an flat iterator.
592
593    Example
594    -------
595    ```py
596    sequence = [1,2,3]
597    for item in aiobungie.into_iter(sequence).reversed():
598        print(item)
599    # 3
600    # 2
601    # 1
602    ```
603
604    Parameters
605    ----------
606    iterable: `typing.Iterable[Item]`
607        The iterable to convert.
608
609    Raises
610    ------
611    `StopIteration`
612        If no elements are left in the iterator.
613    """
614    return FlatIterator(iterable)

Transform an iterable into an flat iterator.

Example
sequence = [1,2,3]
for item in aiobungie.into_iter(sequence).reversed():
    print(item)
# 3
# 2
# 1
Parameters
  • iterable (typing.Iterable[Item]): The iterable to convert.
Raises
  • StopIteration: If no elements are left in the iterator.
async def raise_error( response: aiohttp.client_reqrep.ClientResponse) -> aiobungie.AiobungieError:
229async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError:
230    """Generates and raise exceptions on error responses."""
231
232    # Not a JSON response, raise immediately.
233
234    # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized
235    # request with a dummy access token. I can't really do anything about this..
236    if response.content_type != "application/json":
237        return HTTPError(
238            f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}",
239            http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE,
240        )
241
242    body = await response.json()
243    message: str = body.get("Message", "UNDEFINED_MESSAGE")
244    error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS")
245    message_data: dict[str, str] = body.get("MessageData", {})
246    throttle_seconds: int = body.get("ThrottleSeconds", 0)
247    error_code: int = body.get("ErrorCode", 0)
248
249    # Standard HTTP status.
250    if response.status == http.HTTPStatus.NOT_FOUND:
251        return NotFound(
252            message=message,
253            error_code=error_code,
254            throttle_seconds=throttle_seconds,
255            url=str(response.real_url),
256            body=body,
257            headers=response.headers,
258            error_status=error_status,
259            message_data=message_data,
260        )
261
262    elif response.status == http.HTTPStatus.FORBIDDEN:
263        return Forbidden(
264            message=message,
265            error_code=error_code,
266            throttle_seconds=throttle_seconds,
267            url=str(response.real_url),
268            body=body,
269            headers=response.headers,
270            error_status=error_status,
271            message_data=message_data,
272        )
273
274    elif response.status == http.HTTPStatus.UNAUTHORIZED:
275        return Unauthorized(
276            message=message,
277            error_code=error_code,
278            throttle_seconds=throttle_seconds,
279            url=str(response.real_url),
280            body=body,
281            headers=response.headers,
282            error_status=error_status,
283            message_data=message_data,
284        )
285
286    elif response.status == http.HTTPStatus.BAD_REQUEST:
287        # Membership needs to be alone.
288        if error_status == "InvalidParameters":
289            return MembershipTypeError(
290                message=message,
291                body=body,
292                headers=response.headers,
293                url=str(response.url),
294                membership_type=message_data["membershipType"],
295                required_membership=message_data["membershipInfo.membershipType"],
296                membership_id=int(message_data["membershipId"]),
297            )
298        return BadRequest(
299            message=message,
300            body=body,
301            headers=response.headers,
302            url=str(response.url),
303        )
304
305    status = http.HTTPStatus(response.status)
306
307    if 400 <= status < 500:
308        return ResponseError(
309            message=message,
310            error_code=error_code,
311            throttle_seconds=throttle_seconds,
312            url=str(response.real_url),
313            body=body,
314            headers=response.headers,
315            error_status=error_status,
316            message_data=message_data,
317            http_status=status,
318        )
319
320    # Need to self handle ~5xx errors
321    elif 500 <= status < 600:
322        # No API key or method requires OAuth2 most likely.
323        if error_status in {
324            "ApiKeyMissingFromRequest",
325            "WebAuthRequired",
326            "ApiInvalidOrExpiredKey",
327            "AuthenticationInvalid",
328            "AuthorizationCodeInvalid",
329        }:
330            return Unauthorized(
331                message=message,
332                error_code=error_code,
333                throttle_seconds=throttle_seconds,
334                url=str(response.real_url),
335                body=body,
336                headers=response.headers,
337                error_status=error_status,
338                message_data=message_data,
339            )
340
341        # Anything contains not found.
342        elif (
343            "NotFound" in error_status or error_status == "UserCannotFindRequestedUser"
344        ):
345            return NotFound(
346                message=message,
347                error_code=error_code,
348                throttle_seconds=throttle_seconds,
349                url=str(response.real_url),
350                body=body,
351                headers=response.headers,
352                error_status=error_status,
353                message_data=message_data,
354            )
355
356        # Other 5xx errors.
357        else:
358            return InternalServerError(
359                message=message,
360                error_code=error_code,
361                throttle_seconds=throttle_seconds,
362                url=str(response.real_url),
363                body=body,
364                headers=response.headers,
365                error_status=error_status,
366                message_data=message_data,
367                http_status=status,
368            )
369    # Something else.
370    else:
371        return HTTPException(
372            message=message,
373            error_code=error_code,
374            throttle_seconds=throttle_seconds,
375            url=str(response.real_url),
376            body=body,
377            headers=response.headers,
378            error_status=error_status,
379            message_data=message_data,
380            http_status=status,
381        )

Generates and raise exceptions on error responses.

def stringify_http_message(headers: 'collections.Mapping[str, str]') -> str:
384def stringify_http_message(headers: collections.Mapping[str, str]) -> str:
385    return (
386        "{ \n"
387        + "\n".join(  # noqa: W503
388            f"{f'   {key}'}: {value}"
389            if key not in ("Authorization", "X-API-KEY")
390            else f"   {key}: HIDDEN_TOKEN"
391            for key, value in headers.items()
392        )
393        + "\n}"  # noqa: W503
394    )